etch API 提供了一個 JavaScript接口,用于訪問和操縱HTTP管道的部分,例如請求和響應(yīng)。它還提供了一個全局 fetch()方法,該方法提供了一種簡單,合理的方式來跨網(wǎng)絡(luò)異步獲取資源。
請注意,fetch規(guī)范與jQuery.ajax()主要有兩種方式的不同,牢記:
當(dāng)接收到一個代表錯誤的 HTTP 狀態(tài)碼時,從 fetch()返回的 Promise 不會被標(biāo)記為 reject, 即使該 HTTP 響應(yīng)的狀態(tài)碼是 404 或 500。相反,它會將 Promise 狀態(tài)標(biāo)記為 resolve (但是會將 resolve 的返回值的 ok 屬性設(shè)置為 false ),僅當(dāng)網(wǎng)絡(luò)故障時或請求被阻止時,才會標(biāo)記為 reject。
默認(rèn)情況下,fetch 不會從服務(wù)端發(fā)送或接收任何 cookies, 如果站點依賴于用戶 session,則會導(dǎo)致未經(jīng)認(rèn)證的請求(要發(fā)送 cookies,必須設(shè)置 credentials 選項)。自從2017年8月25日后,默認(rèn)的credentials政策變更為same-originFirefox也在61.0b13中改變默認(rèn)值
fetch('http://example.com/movies.json') .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); });
這里我們通過網(wǎng)絡(luò)獲取一個JSON文件并將其打印到控制臺。最簡單的用法是只提供一個參數(shù)用來指明想fetch()到的資源路徑,然后返回一個包含響應(yīng)結(jié)果的promise(一個 Response 對象)。
當(dāng)然它只是一個 HTTP 響應(yīng),而不是真的JSON。為了獲取JSON的內(nèi)容,我們需要使用 json()方法(在Bodymixin 中定義,被 Request 和 Response 對象實現(xiàn))。
fetch() 接受第二個可選參數(shù),一個可以控制不同配置的 init 對象:
// Example POST method implementation: postData('http://example.com/answer', {answer: 42}) .then(data => console.log(data)) // JSON from `response.json()` call .catch(error => console.error(error)) function postData(url, data) { // Default options are marked with * return fetch(url, { body: JSON.stringify(data), // must match 'Content-Type' header cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, same-origin, *omit headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin redirect: 'follow', // manual, *follow, error referrer: 'no-referrer', // *client, no-referrer }) .then(response => response.json()) // parses response to JSON }
更多內(nèi)容:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
新手課程中,我們建立了一個非常簡單的dApp,使用HTML、CSS和一些JavaScript。然而,在現(xiàn)實世界中,這些類型的"vanilla"網(wǎng)站實現(xiàn)已經(jīng)是過去式了。
今天,我們使用web框架來簡化web開發(fā)過程。但它更簡單嗎?取決于你從誰的角度看問題。如果你剛剛開始,以前從未做過這件事,那么你可能需要一段時間才能理解所有必要的概念。但是,從長遠(yuǎn)來看,你會感謝自己,并為自己花時間學(xué)習(xí)而感到高興。
現(xiàn)在最大和最常用的網(wǎng)絡(luò)框架是:
雖然它們各有優(yōu)缺點,但到目前為止,React已經(jīng)在Web開發(fā)領(lǐng)域掀起了風(fēng)暴。在Web3領(lǐng)域也是如此,React是構(gòu)建dApps最常用的網(wǎng)絡(luò)框架。在整個新手課程中,以及所有以后的課程中,我們將使用大量的React,所以可以把這個級別看作是React的速成課程,它將教會你足夠的東西來開始。這并不是要取代在專注于Web2教學(xué)的平臺上學(xué)習(xí)React,而是作為一個指南,讓你了解有多少東西是必須開始學(xué)習(xí)的,這樣你就不會陷入教程的地獄。
實際上,我們將使用Next.js--它是React本身的一個擴展--但后面會有更多的內(nèi)容。讓我們先學(xué)習(xí)一些React。
React是一個網(wǎng)絡(luò)框架,它使得構(gòu)建和響應(yīng)你的網(wǎng)絡(luò)應(yīng)用的 "視圖 "變得容易。視圖 "是在屏幕上顯示的內(nèi)容,它如何變化,如何更新,等等。React本質(zhì)上只是給你一個模板語言,你可以創(chuàng)建返回HTML的Javascript函數(shù)。
正常的Javascript函數(shù)會返回Javascript相關(guān)的東西--字符串、數(shù)字、布爾值、對象等等。React基本上結(jié)合了Javascript和HTML,產(chǎn)生了一種他們稱之為JSX的語言。在JSX中,類似Javascript的函數(shù)返回HTML,而不是常規(guī)的Javascript事物。基本上就是這樣了。
返回HTML的Javascript函數(shù)的組合被稱為組件。組件是用JSX編寫的。雖然一開始看起來很笨拙,但一旦你習(xí)慣了,它們實際上是很容易操作的。
下面是一個簡單組件的例子。
function ShoppingList() {
return (
<div className="shopping-list">
<h1>Shopping List</h1>
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Grapes</li>
</ul>
</div>
);
}
運行代碼[4]
很好,但這與HTML沒有什么區(qū)別。但是,如果你想根據(jù)一個數(shù)組來呈現(xiàn)一個項目的列表呢?
function ShoppingList() {
const items = ["Apples", "Bananas", "Grapes"]
return (
<div className="shopping-list">
<h1>Shopping List</h1>
<ul>
{items.map((item, index) => <li key={index}>{item}</li>)}
</ul>
</div>
);
}
運行代碼[5]
哇,看看這個! 我們剛剛在HTML中使用了Javascript。在JSX中,你可以通過用大括號{和}包裹JS代碼在HTML中編寫Javascript。實際上,如果你多想一下,你就會明白發(fā)生了什么。.map()是一個Javascript函數(shù),它在一個數(shù)組上循環(huán),并為每個項目返回一些東西。在這種情況下,它在 items 數(shù)組上循環(huán),并返回一個 li 元素,其中有 Javascript 變量 item 的值,也就是 HTML。明白了嗎?
在我們的組件中,我們基本上嵌入了另一個組件。map函數(shù)是一個返回HTML的JS函數(shù)。它是一個組件。盡管它沒有被明確定義為頂級函數(shù),它仍然是一個組件。
將組件嵌入到其他組件中是 React 的強大功能。這稱為組合。我們將多個返回 HTML 的 Javascript 函數(shù)組合在一起,并從中構(gòu)建一個組合的 HTML 文檔,該文檔將顯示在 Web 應(yīng)用程序上。
如果組件只是靜態(tài)的,它們就不是很有用。當(dāng)然,遍歷數(shù)組和其他東西都很好,但當(dāng)今大多數(shù) Web 應(yīng)用程序都不是靜態(tài)文檔。今天的大多數(shù) Web 應(yīng)用程序都會從某種服務(wù)器、數(shù)據(jù)庫或區(qū)塊鏈中動態(tài)獲取數(shù)據(jù)。這意味著經(jīng)常需要相同的組件來顯示不同的數(shù)據(jù)。
擁有組件的主要用例是能夠編寫可重用的代碼,并且可以在其中包含不同的信息,而無需再次重寫整個代碼。
讓我們看一個例子。這兩個代碼哪個更易讀?
<div class="cards">
<div class="card">
<img src="img_avatar.png" alt="Avatar">
<div class="container">
<h4><b>Alice</b></h4>
<p>Frontend Developer</p>
</div>
</div>
<div class="card">
<img src="img_avatar.png" alt="Avatar">
<div class="container">
<h4><b>Bob</b></h4>
<p>Backend Developer</p>
</div>
</div>
<div class="card">
<img src="img_avatar.png" alt="Avatar">
<div class="container">
<h4><b>Charlie</b></h4>
<p>Full Stack Developer</p>
</div>
</div>
</div>
function Cards() {
return (
<div className="cards">
<!--Data is passed to children through HTML attributes-->
<Card name="Alice" job="Frontend Developer" />
<Card name="Bob" job="Backend Developer" />
<Card name="Charlie" job="Full Stack Developer" />
</div>
)
}
// Card receives an object as an argument
// We can destructure the object to get specific variables
// from inside the object - name and job
function Card({name, job}) {
return (
<div className="card">
<img src="img_avatar.png" />
<div className="container">
<h4><b>{name}</b></h4>
<p>{job}</p>
</div>
</div>
)
}
運行代碼[6]
純 HTML 示例重復(fù)使用相同的代碼 3 次,盡管真正改變的只是人名和他們的職位。
在 JSX 中,我們可以將每個組件抽象Card為一個組件,該組件從其父組件(在本例中為 )獲取某些數(shù)據(jù)Cards。父組件通過類似 HTML 的屬性name="Alice"(然后,Card組件可以根據(jù)從父級接收到的內(nèi)容返回帶有可變數(shù)據(jù)的 HTML。
這段代碼更容易重用和擴展。想要稍微改變所有卡片的外觀嗎?只需修改一個組件!并非所有復(fù)制粘貼的 HTML。
好的,所以我們現(xiàn)在可以在組件之間傳遞數(shù)據(jù)。這一切都很好,但我們還沒有添加交互性。諸如在單擊按鈕或在輸入框中鍵入文本時能夠運行一些代碼等。
值得慶幸的是,在 Javascript 中,函數(shù)可以在其中包含函數(shù)。例如,
function someFunc() {
function otherFunc() {
console.log("Hello!")
}
otherFunc();
}
someFunc(); // will print "Hello!"
otherFunc(); // will throw an error! undefined here
otherFunc只能在someFunc自身內(nèi)部使用。這是常規(guī) Javascript 中很少使用的功能,但在使用 React 時使用非常頻繁。讓我們通過一個例子來看看為什么。
function Button() {
function handleClick() {
console.log("Hello")
}
return (
<button
className="button"
onClick={handleClick}>
Click Me!
</button>
)
}
運行代碼[7]
我們有一個名為Button. 在這個函數(shù)中,我們有另一個函數(shù)叫做handleClick。在 HTML<button>標(biāo)記中,我們指定onClick={handleClick}當(dāng)單擊按鈕時handleClick調(diào)用該函數(shù)。此功能僅在Button組件內(nèi)部可用。單擊 Web 應(yīng)用程序上的按鈕將Hello在瀏覽器控制臺中打印。這就是我們使用 React 構(gòu)建交互式網(wǎng)站的方式!
這個例子仍然相當(dāng)簡單,因為handleClick沒有參數(shù)。如果我們想在用戶輸入輸入框時在控制臺中打印文本怎么辦?我們?nèi)绾螌⑽谋緜鬟f給函數(shù)?
就是這樣。
function PrintTypedText() {
function handleOnChange(text) {
console.log(text);
}
return (
<input
type="text"
onChange={(e) => handleOnChange(e.target.value)}
/>
)
}
運行代碼[8]
HTMLinput元素提供了一個方便的事件偵聽器 -onChange每次輸入框中的文本發(fā)生更改(鍵入新字符、刪除字符等)時都會觸發(fā)該事件偵聽器。
但是,除了觸發(fā)一個函數(shù)之外,它還傳遞了更改的 HTML 元素(在e此處引用)。然后我們可以獲取 HTML 元素e并使用提取文本e.target.value并將其作為參數(shù)傳遞給該參數(shù),該參數(shù)handleOnChange會將文本記錄到瀏覽器控制臺。
不同的 HTML 元素有不同的事件處理程序 -這是兩個示例onChange,onClick但還有更多!您可以在此處[9]找到所有 HTML 事件的列表。
通過將 HTML 事件與函數(shù)處理程序相結(jié)合,我們可以做各種很酷的事情!從服務(wù)器加載數(shù)據(jù)、向服務(wù)器發(fā)送數(shù)據(jù)、更新我們的視圖等。
好的,我們已經(jīng)討論了組合、數(shù)據(jù)傳遞和交互性。但是,我們的應(yīng)用程序仍然很愚蠢。交互性將允許您在單擊按鈕等時運行一些代碼,但是如果您想更新一些變量怎么辦?
不幸的是,以下不起作用
function DoesNotWork() {
let myNumber = 0;
function increment() {
myNumber++;
}
return (
<div>
<p>{myNumber}</p>
<button onClick={increment}>Increment!</button>
</div>
)
}
運行代碼[10]
無論點擊多少次Increment,屏幕上顯示的數(shù)字都會卡在0。這是因為當(dāng)您像myNumber從 React 組件中更新常規(guī)變量時,即使值已更新,React 實際上也不會重新渲染 Web 應(yīng)用程序的視圖。它不會自動更新頁面的 HTML 視圖。
React Hooks 是“掛鉤”到 React 組件的不同部分的函數(shù),允許您執(zhí)行諸如在變量值更改時更新視圖,或在每次加載頁面或更改變量時自動運行一些 JS 代碼等操作,以及許多更酷的東西!我們將主要關(guān)注 95% 的時間使用的三個 React 鉤子 - useState、useEffect和useRef。
很多時候,您希望 HTML 視圖根據(jù)某些變量的值變化進(jìn)行更新。我們可以使用該useState鉤子來維護(hù)一個變量,該變量會在每次更改其值時自動重新渲染屏幕上顯示的 HTML。這是一個例子:
function ThisWorks() {
// myNumber is the variable itself
// setMyNumber is a function that lets us update the value
// useState(0) initializes the React Hook
// with the starting value of 0
const [myNumber, setMyNumber] = useState(0);
function increment() {
// Sets the new value to the old value + 1
setMyNumber(myNumber + 1);
}
return (
<div>
<p>{myNumber}</p>
<button onClick={increment}>Increment!</button>
</div>
)
}
運行代碼[11]
如果您嘗試運行上述代碼,您將看到 Web 應(yīng)用程序的視圖自動更新以反映變量的新值。
useState在 React 中使用創(chuàng)建的變量稱為狀態(tài)變量。狀態(tài)變量可以更新并自動更新應(yīng)用程序的視圖。這是另一個在輸入框中使用狀態(tài)變量的示例。
function StateWithInput() {
// myName is the variable
// setMyName is the updater function
// Create a state variable with initial value
// being an empty string ""
const [myName, setMyName] = useState("");
function handleOnChange(text) {
setMyName(text);
}
return (
<div>
<input type="text" onChange={(e) => handleOnChange(e.target.value)} />
<p>Hello, {myName}!</p>
</div>
)
}
運行代碼[12]
我們看到 HTML 上顯示的文本隨著輸入框內(nèi)容的變化而變化。偉大的!
關(guān)于 useState,我想說的最后一件事是,您還可以將它用于字符串和數(shù)字等基本類型。您還可以使用它們來存儲數(shù)組和對象。但是,這里有一個警告。讓我們看一個例子:
function StateArrayDoesNotWork() {
const [fruits, setFruits] = useState([]);
const [currentFruit, setCurrentFruit] = useState("");
function updateCurrentFruit(text) {
setCurrentFruit(text);
}
function addFruitToArray() {
fruits.push(currentFruit);
}
return (
<div>
<input type="text" onChange={(e) => updateCurrentFruit(e.target.value)} />
<button onClick={addFruitToArray}>Add Fruit</button>
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
</div>
);
}
運行代碼[13]
如果您嘗試運行它,您將看到屏幕上沒有顯示任何水果。另請注意,我們沒有在setFruits任何地方使用該函數(shù),而只是嘗試.push使用fruits數(shù)組。
當(dāng)我們嘗試直接更新數(shù)組時,React 不會注冊狀態(tài)更改,這也被認(rèn)為是無效的狀態(tài)更新,可能導(dǎo)致應(yīng)用程序出現(xiàn)意外行為。我們知道我們需要以某種方式使用setFruits,但是如何使用呢?答案是我們實際上需要創(chuàng)建水果數(shù)組的副本,將水果添加到其中,并將狀態(tài)變量完全設(shè)置為新數(shù)組。下面的例子:
function StateArray() {
const [fruits, setFruits] = useState([]);
const [currentFruit, setCurrentFruit] = useState("");
function updateCurrentFruit(text) {
setCurrentFruit(text);
}
function addFruitToArray() {
// The spread operator `...fruits` adds all elements
// from the `fruits` array to the `newFruits` array
// and then we add the `currentFruit` to the array as well
const newFruits = [...fruits, currentFruit]
setFruits(newFruits);
}
return (
<div>
<input type="text" onChange={(e) => updateCurrentFruit(e.target.value)} />
<button onClick={addFruitToArray}>Add Fruit</button>
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
</div>
);
}
運行效果[14]
如果您嘗試運行上述代碼,您將看到它按預(yù)期工作。每次按下按鈕時,輸入框中的當(dāng)前文本都會添加到數(shù)組中,這會導(dǎo)致 HTML 上顯示的水果列表更新。您可以繼續(xù)添加任意數(shù)量的水果!
對象也是如此。如果您的狀態(tài)變量包含一個對象,您需要先創(chuàng)建該對象的副本,更新一個值,然后將狀態(tài)變量完全設(shè)置為新對象。
所以我們現(xiàn)在可以管理狀態(tài),太好了!狀態(tài)變化也會影響我們渲染的 HTML,也很棒!
但是,通常需要在第一次加載頁面時自動運行一些代碼——可能是從服務(wù)器或區(qū)塊鏈獲取數(shù)據(jù)——并且還需要在某個狀態(tài)變量發(fā)生變化時自動運行一些代碼。
這些類型的功能稱為副作用。React 為我們提供了useEffect允許我們編寫這些效果的鉤子。useEffect接受兩個參數(shù) - 一個函數(shù)和一個依賴數(shù)組。函數(shù)是運行效果時運行的代碼,依賴數(shù)組指定何時觸發(fā)副作用。
考慮一個示例,當(dāng)網(wǎng)站首次加載時,它想從服務(wù)器加載一些數(shù)據(jù)。這樣做時,它希望向用戶顯示一個加載屏幕,然后在加載數(shù)據(jù)后,移除加載屏幕并顯示實際內(nèi)容。我們?nèi)绾巫龅竭@一點?
function LoadDataFromServer() {
// Create a state variable to hold the data returned from the server
const [data, setData] = useState("");
// Create a state variable to maintain loading state
const [loading, setLoading] = useState(false);
async function loadData() {
// Set `loading` to `true` until API call returns a response
setLoading(true);
// Imaginary function that performs an API call to load
// data from a server
const data = await apiCall();
setData(data);
// We have the data, set `loading` to `false`
setLoading(false);
}
// loadData is the function that is run
// An empty dependency array means this code is run
// once when the page loads
useEffect(() => {
loadData();
}, []);
// Display `"Loading..."` while `loading` is `true`,
// otherwise display `data`
return <div>{loading ? "Loading..." : data}</div>;
}
運行代碼[15]
如果您從鏈接運行上述代碼,您將看到它Loading...在屏幕上顯示 5 秒鐘,然后顯示ABCDEF. 這是因為apiCall是一個等待 5 秒然后返回字符串的函數(shù)ABCDEF。
首次加載頁面時的useEffect調(diào)用loadData(由于依賴項數(shù)組為空)和狀態(tài)變量使 HTML 呈現(xiàn)適當(dāng)?shù)膬?nèi)容。
這對于在頁面第一次加載時運行代碼很有用,但是每次狀態(tài)變量的值發(fā)生變化時運行一些代碼呢?例如,當(dāng)您在 Facebook 上搜索某人的姓名時,F(xiàn)acebook 如何在您每次添加/刪除角色時獲取并顯示推薦?
你也可以useEffect通過在依賴數(shù)組中提供狀態(tài)變量來做到這一點。每次該變量的值發(fā)生變化時,都會運行效果。
function DependentEffect() {
const names = ["Alice", "Bob", "Charlie", "David", "Emily"];
const [recommendations, setRecommendations] = useState([]);
const [searchText, setSearchText] = useState("");
useEffect(() => {
// If user is not searching for anything, don't show any recomendations
if (searchText.length === 0) {
setRecommendations([]);
}
// Else, find recommendations
else if (searchText.length > 0) {
const newRecs = names.filter((name) =>
name.toLowerCase().includes(searchText.toLowerCase())
);
setRecommendations(newRecs);
}
}, [searchText]);
return (
<div>
<input type="text" onChange={(e) => setSearchText(e.target.value)} />
<h2>Recommendations:</h2>
<ul>
{recommendations.map((rec, index) => (
<li key={index}>{rec}</li>
))}
</ul>
</div>
);
}
運行代碼[16]
如果您運行上述代碼并嘗試輸入一些字母,您將看到推薦列表會隨著您在搜索框中添加/刪除新字符而自動更新。這是因為當(dāng)你更新輸入框時,searchText是通過onChange處理程序更新的,它觸發(fā)了useEffect,它更新了recommendations列表,它更新了 HTML 視圖。
您也可以類似地創(chuàng)建依賴于多個狀態(tài)變量的副作用,而不僅僅是一個。如果任何因變量發(fā)生變化,就會產(chǎn)生副作用。您只需將更多狀態(tài)變量添加到依賴項數(shù)組即可。
useEffect(() => {
// Some code
}, [stateVar1, stateVar2, stateVar3, andSoOn])
useRef是另一個比較常用的 React 鉤子。它與表面上非常相似useState,但有一些實際上非常重要的細(xì)微差別使得這個 React Hook 學(xué)習(xí)起來很重要。
useRef變量創(chuàng)建如下:
function Component() {
const myValue = useRef();
function updateMyValue(newValue) {
myValue.current = newValue;
}
function printMyValue() {
console.log(myValue.current);
}
}
與類似useState,useRef鉤子還允許我們將變量存儲在可以隨時間更新的組件中。但是,與狀態(tài)變量不同,更新 ref 變量的值不會導(dǎo)致 HTML 視圖重新呈現(xiàn)。
因此,如果您有一個useRef變量并且您在 HTML 視圖中顯示它的值,則更新該變量不會更新 HTML 視圖。
function CounterWithRef() {
const myNumber = useRef();
function increment() {
if (myNumber.current !== undefined) {
myNumber.current += 1;
} else {
myNumber.current = 1;
}
console.log(myNumber.current);
}
return (
<div>
<p>{myNumber}</p>
<button onClick={increment}>Increment!</button>
</div>
)
}
運行代碼[17]
如果您運行上面的代碼,您會注意到每次單擊按鈕時,值都會遞增并打印在瀏覽器控制臺中,但 HTML 視圖實際上并沒有更新。事實上,HTML 視圖不顯示任何內(nèi)容,因為 is 的初始值,myNumber.current并且undefined由于 HTML 沒有更新,因此undefined即使值實際上正在更新,它仍然保持與 HTML 相關(guān)的內(nèi)容。
我們之前沒有提到useState的是,當(dāng)我們使用setXYZ函數(shù)更新狀態(tài)變量時,它實際上并沒有立即更新。
在 React 中為狀態(tài)變量設(shè)置新值是異步發(fā)生的,這意味著如果您在將狀態(tài)變量設(shè)置為新值后立即嘗試使用它的值,您可能實際上看不到新值被反映,因為它是異步發(fā)生的。
我們再看一下使用時的Counter例子useState。
function AsyncStateVariables() {
const [number, setNumber] = useState(0);
function increment() {
setNumber(number + 1);
console.log(number);
}
return (
<div>
<p>{number}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
運行代碼[18]
當(dāng)您運行它時,請注意視圖上發(fā)生了什么以及控制臺中發(fā)生了什么。當(dāng)您第一次單擊按鈕時,狀態(tài)變量應(yīng)該更新為1- 這就是視圖上發(fā)生的情況,網(wǎng)頁顯示1. 但是,如果您查看瀏覽器控制臺,0則會打印該值而不是1. 當(dāng)您繼續(xù)單擊按鈕時,此模式將繼續(xù)。
這是因為setNumber調(diào)用是異步運行的,當(dāng)我們到達(dá)該console.log(number)行時,該值尚未更新,因此它會打印number. 當(dāng)它確實被更新時,HTML 被重新渲染以顯示新值。
useRef另一方面,允許同步更新。當(dāng)您使用它更新引用變量的值時,myVar.current = newValue它會立即更新,并且沒有延遲。這有時會派上用場。
讓我們做的另一件很酷的事情useRef是它允許我們直接引用 DOM 元素。這是useState.
例如,您可以input使用直接引用元素useRef
function InputFocus() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
運行代碼[19]
當(dāng)您運行上面的示例時,您會注意到頁面加載后,該input元素已經(jīng)處于焦點位置,即您可以開始輸入而無需先單擊它。這是因為我們持有一個對input元素的引用,并且useEffect由于有一個空的依賴數(shù)組,它在頁面加載時運行,它專注于input元素。
太好了,如果你剛剛開始使用 React,我們已經(jīng)介紹了你應(yīng)該知道的主要概念。但到目前為止,我們只處理了孤立的組件示例。一個實際的 React 項目是什么樣子的?
React 應(yīng)用程序通常使用create-react-app(CRA)之類的工具創(chuàng)建。CRA 是一個命令行工具,可幫助您設(shè)置新的 React 項目并安裝所有必需的依賴項,而無需手動創(chuàng)建所有樣板。
當(dāng)您使用 CRA 時,您最終會得到如下所示的文件結(jié)構(gòu)。
該package.json文件應(yīng)該是可識別的。CRA 通過 Node.js 環(huán)境工作,并且package.json是創(chuàng)建所有依賴項和項目元數(shù)據(jù)的地方 - 與任何其他 Node.js 項目一樣。
該src/文件夾包含組件和 CSS 樣式,基本上是任何特定于 React 的代碼。這里的主要組件是App.js,它是您第一次設(shè)置 React 應(yīng)用程序時創(chuàng)建的自動生成的組件。index.js是 React 應(yīng)用程序的主要入口點,但通常你不需要太多(或根本不需要)修改它。它只包含一些樣板 React 代碼,這些代碼獲取您的組件并將其轉(zhuǎn)換為可以在瀏覽器中運行的實際 HTML 和 JS。
然后該public/文件夾默認(rèn)只包含一個文件 - index.html. 你通常不會自己碰這個。這是一個超級簡單的準(zhǔn)系統(tǒng) HTML 文件。當(dāng)一個 React 應(yīng)用程序運行時,React 會在后臺執(zhí)行一些魔法,它會獲取所有組件和 Javascript 代碼,將其轉(zhuǎn)換為可以在瀏覽器中運行的實際 HTML 和 JS,并index.html用所有這些替換其中的內(nèi)容。然后,更新index.html的就是向用戶顯示的內(nèi)容。
如果您想將圖像、字體、音樂等添加到您的網(wǎng)站,它們也會進(jìn)入該public/文件夾。該public/文件夾基本上包含您希望在您的網(wǎng)站上直接訪問的所有內(nèi)容。
例如,如果您在文件夾中添加了一個名為的圖像avatar.png,public/那么您可以在 React 組件中顯示該圖像,如下所示:
<img src="/avatar.png" />
雖然這可能看起來很奇怪,因為您的組件位于src/文件夾中而不是public/文件夾中 - 它工作的原因是因為圖像與位于同一文件夾中index.html- 并且index.html是您的 React 代碼實際結(jié)束的地方。因此,當(dāng)使用 的相對路徑引用圖像時/avatar.png,它知道它avatar.png必須在public文件夾內(nèi)。
到目前為止,我們一直在討論 React,以及它的所有前端功能。但是后端呢?
React 不是后端框架,因此如果您想創(chuàng)建自己的 API 后端,則必須使用 Node.js 和 Express 之類的東西建立一個單獨的項目。然而這很麻煩,就好像后端和前端是同一個項目一樣,你可能有很多代碼可以在兩者之間重用和共享。此外,維護(hù)兩個項目總是比只維護(hù)一個項目更難。
輸入,Next.js
接下來是 React 的元框架。這是什么意思?嗯,React 本身就是一個構(gòu)建 Web 應(yīng)用程序的框架。接下來是一個 React 框架,它還引入了一些 React 沒有的附加功能。
如果你了解 React,那么 Next 90% 是完全一樣的東西,你可以很快開始使用它,但是我想談?wù)?Next 帶來的這些額外功能。
首先,正如標(biāo)題和介紹所暗示的那樣,Next 允許您在單個項目中編寫前端和后端代碼。您使用 React 構(gòu)建前端,并使用與使用 Express 類似的語法編寫后端 API 端點 - 但都在同一個項目中。
其次,Next 使創(chuàng)建多頁 Web 應(yīng)用程序變得非常容易。React 最初旨在幫助創(chuàng)建單頁應(yīng)用程序(SPA),組件非常適合!但是,如果您的網(wǎng)站有多個頁面怎么辦?例如https://learnweb3.io/和https://learnweb3.io/about等等https://learnweb3.io/tracks。
為此,React Router引入了諸如此類的庫,這使之成為可能,但也有點麻煩。“下一步”通過允許基于文件名的自動頁面路由大大簡化了這一點。
最后,Next 還具有服務(wù)器端渲染 (SSR) 和靜態(tài)站點生成 (SSG)。這些不是我們將在我們的曲目中使用的功能,所以我不會在這里花太多時間,但如果您想了解更多關(guān)于它們的信息,請隨時閱讀推薦閱讀。
在討論創(chuàng)建后端服務(wù)器之前,我們將討論路由,因為這將幫助您了解它是如何工作的。
類似于create-react-app,Next 有一個名為的工具create-next-app,可以自動幫助您輕松設(shè)置新的 Next.js 項目。
當(dāng)您創(chuàng)建一個新的 Next.js 項目時,您最終會得到一個如下所示的文件結(jié)構(gòu):
這是很多文件!但別擔(dān)心,其中很多與我們已經(jīng)討論過的 React 類似。
該public/文件夾的工作方式完全相同,但不包含index.html文件。但是,如果您想添加圖像、圖標(biāo)、字體、音樂等,您可以將它們?nèi)糠旁?span style="color: #DD1144; --tt-darkmode-color: #DD1144;">public/文件夾中。
該styles/文件夾是一個很好的補充,為您的所有 CSS 文件提供了一個專用位置。
這pages/就是偉大的。_app.js是一個自動生成的文件,通常您不會自己接觸它,并設(shè)置了一些樣板代碼,允許 Next 呈現(xiàn)正確的組件。
pages/index.js是您網(wǎng)站的主頁。基本上,文件pages夾中的每個文件都是您網(wǎng)站的路線。遵循 Javascript/HTML 樣式的命名約定,這意味著index文件是“主”文件。因此,pages/index.js當(dāng)您第一次打開您的網(wǎng)站時將加載的視圖。
如果您在pages文件夾下添加更多文件,例如一個名為about.js- 的文件,它將在YOUR_DOMAIN/about(有趣的事實:LearnWeb3 的網(wǎng)站是使用 Next 創(chuàng)建的,這正是我們https://learnweb3.io/about頁面的工作方式)。
這很棒,因為您不必處理諸如 React Router 之類的事情,并且構(gòu)建多頁網(wǎng)站就像在pages/文件夾下創(chuàng)建一個新文件一樣簡單,Next 會自動為您生成基于文件名的路由。
您還可以通過在文件夾下創(chuàng)建子文件夾來進(jìn)行多級路由pages/。例如,類似pages/tracks/freshman.js的東西會有 route YOUR_DOMAIN/tracks/freshman。
然而,下面有一個特殊的文件夾,pages/它也是自動生成的。pages/api文件夾。與呈現(xiàn) HTML 視圖的常規(guī)頁面不同,pages/api文件夾下的任何內(nèi)容都充當(dāng) API 端點。
讓我們看一下自動生成的pages/api/hello.js文件:
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
這是一個非常類似于 Express 的功能。如果你要去YOUR_DOMAIN/api/hello- 而不是呈現(xiàn) HTML 視圖,這將返回一個 JSON 對象{name: 'John Doe'}- 這是一個超級簡單的 API 端點。
與常規(guī)的 HTML 視圖類似,您可以pages/api通過創(chuàng)建新文件來創(chuàng)建 API 端點,并且端點路由基于文件名。
我希望這篇文章對您有所幫助,并且可以作為速成課程。我故意在這里更多地關(guān)注 React 而不是 Next,因為習(xí)慣前端部分對我們來說將比后端部分更相關(guān)。此外,后端代碼基本上是常規(guī)的 Javascript,而前端是 JSX,我想讓你更熟悉它。
[1] React: https://reactjs.org/
[2] Angular: https://angular.io/
[3] Vue: https://vuejs.org/
[4] 運行代碼: https://codesandbox.io/s/icy-water-xrm2ch?file=/src/App.js
[5] 運行代碼: https://codesandbox.io/s/confident-tesla-5l3k1t?file=/src/App.js
[6] 運行代碼: https://codesandbox.io/s/zealous-carson-44om2s?file=/src/App.js
[7] 運行代碼: https://codesandbox.io/s/quizzical-sammet-59fi5i?file=/src/App.js
[8] 運行代碼: https://codesandbox.io/s/mutable-feather-el4sbe?file=/src/App.js
[9] 您可以在此處: https://www.w3schools.com/jsref/dom_obj_event.asp
[10] 運行代碼: https://codesandbox.io/s/romantic-euclid-44hh8x
[11] 運行代碼: https://codesandbox.io/s/intelligent-hoover-31bwmg
[12] 運行代碼: https://codesandbox.io/s/young-microservice-c1e5be?file=/src/App.js
[13] 運行代碼: https://codesandbox.io/s/kind-jasper-vbs0f9?file=/src/App.js
[14] 運行效果: https://codesandbox.io/s/suspicious-monad-gpes3r?file=/src/App.js
[15] 運行代碼: https://codesandbox.io/s/practical-cache-ib3c0f?file=/src/App.js:186-756
[16] 運行代碼: https://codesandbox.io/s/cold-darkness-eub0eh?file=/src/App.js
[17] 運行代碼: https://codesandbox.io/s/small-paper-9ecbfp?file=/src/App.js
[18] 運行代碼: https://codesandbox.io/s/reverent-lichterman-k4n448?file=/src/App.js
[19] 運行代碼: https://codesandbox.io/s/input-focus-zntci?file=/src/App.js
[20] 30 分鐘學(xué)會 React: https://www.youtube.com/watch?v=hQAHSlTtcmY
[21] Next.js in 100 Seconds // 加上完整的教程: https://www.youtube.com/watch?v=Sklc_fQBmcs
[22] Scrimba 的完整 React 課程: https://scrimba.com/learn/learnreact
[23] Next.js 速成班: https://www.youtube.com/watch?v=mTz0GXj8NN0
言:
一位前端界的大神讓我去思考的一個問題, 給了Big-man一段代碼,如下:
function Seriously(options) { // if called without 'new', make a new object and return that if(window === this || !(this instanceof Seriously) || this.id !== undefined) { return new Seriously(options); } }
return語句執(zhí)行之后還會繼續(xù)執(zhí)行嗎?這是大神上來讓我解決的問題,既然提到了return那我也就隨帶解決JS中另外的兩種結(jié)束循環(huán)的方法break, continue。
Break語句:
break語句會使運行的程序立刻退出包含在最內(nèi)層的循環(huán)或者退出一個switch語句。
由于它是用來退出循環(huán)或者switch語句的, 所以只有當(dāng)它出現(xiàn)在這些語句的時候, 這種形式的break語句才是合法的。
如果一個循環(huán)的終止條件非常復(fù)雜, 那么使用break語句來實現(xiàn)某些條件比用一個循環(huán)表達(dá)式所有的條件容易得多。
for(var i = 519; i < 550; i++) { if(i == 522) { break; } console.log(i); alert(i); document.write(i); }
當(dāng)i = 521的時候,直接退出for這個循環(huán)。這個循環(huán)將不再被執(zhí)行。
對于輸出結(jié)果的話,可以自己去測試的吧。
Continue語句:
continue語句和break語句相似。所不同的是,它不是退出一個循環(huán),而是開始循環(huán)的一次新迭代。
continue語句只能用在while語句、do/while語句、for語句、或者for/in語句的循環(huán)體內(nèi), 在其他地方使用都會引起錯誤?
for(var i = 5; i >=0; i--) { if(i == 4 || i == 3 || i == 1) { continue; } console.log(i); alert(i); document.write(i); }
當(dāng)i = 4、i = 3以及i = 1的時候,直接跳出for循環(huán)。下次繼續(xù)執(zhí)行。
至于輸出結(jié)果,還希望大家去打印一下。
Return語句:
return語句就是用于指定函數(shù)返回的值。return語句只能出現(xiàn)在函數(shù)體內(nèi),出現(xiàn)在代碼中的其他任何地方造成語法錯誤!
for(var i = 1; i < 10; i++) { if(i == 8) { return; } console.log(i); alert(i); document.write(i); }
執(zhí)行結(jié)果Uncaught SyntaxError: illegal return statement(...)
錯誤意思是非法捕獲的查詢返回語句。
當(dāng)執(zhí)行return語句時, 即使函數(shù)主題中還有其他語句, 函數(shù)執(zhí)行也會停止!
<script type="text/javascript"> if(username == "") { alert("please input your username: "); return false; } else if (qq == "") { alert("please input your qq number: "); return false; } </script>
上面的實例里,當(dāng)username為空時,就不會再向下執(zhí)行,在一些表單提交中,也可以通過return false來阻止默認(rèn)的提交方式,改用Ajax的提交方式,例如:
<form id="form" onSubmit="return false"> ... </form>
this對應(yīng)的全局變量:
window == this這個Boolean等式,在不同的情況下的展現(xiàn)都不一樣的。
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <script type="text/javascript"> function a() { console.log(window === this) } a(); </script> </body> </html>
這個時候的window === this打印出來的是true,這也就意味著this絕對等于window。
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <script type="text/javascript"> 'use strict' function a() { console.log(window === this) } a(); </script> </body> </html>
這個時候window === this返回回來的值卻是false, 而且打印出來的this是undefined的。
所以嚴(yán)格模式下面的代碼操作需要更加的規(guī)范和合理才可以的。
vector illustration web development shield sign
---------------------
作者:JD9
來源:CSDN
原文:https://blog.csdn.net/XXJ19950917/article/details/78310346
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。