撰写本文的所有基本React.js概念
Update: This article is now part of my book “React.js Beyond The Basics”.
更新:本文現(xiàn)在是我的書《超越基礎(chǔ)的React.js》的一部分。
Read the updated version of this content and more about React at jscomplete.com/react-beyond-basics.
在jscomplete.com/react-beyond-basics中閱讀此內(nèi)容的更新版本以及有關(guān)React的更多信息。
This article is not going to cover what React is or why you should learn it. Instead, this is a practical introduction to the fundamentals of React.js for those who are already familiar with JavaScript and know the basics of the DOM API.
本文不會(huì)介紹什么是React或?yàn)槭裁匆獙W(xué)習(xí)它 。 相反,這是對那些已經(jīng)熟悉JavaScript并了解DOM API基礎(chǔ)知識(shí)的人的React.js基礎(chǔ)知識(shí)的實(shí)用介紹。
All code examples below are labeled for reference. They are purely intended to provide examples of concepts. Most of them can be written in a much better way.
以下所有代碼示例均已標(biāo)記為參考。 它們純粹是為了提供概念的示例。 它們中的大多數(shù)可以用更好的方式編寫。
基本原理1:React完全涉及組件 (Fundamental 1: React is all about components)
React is designed around the concept of reusable components. You define small components and you put them together to form bigger components.
React是圍繞可重用??組件的概念設(shè)計(jì)的。 您定義小組件,然后將它們放在一起以形成更大的組件。
All components small or big are reusable, even across different projects.
所有大小的組件都可以重用,即使在不同的項(xiàng)目中也可以重用。
A React component — in its simplest form — is a plain-old JavaScript function:
一個(gè)最簡單的形式的React組件是一個(gè)普通JavaScript函數(shù):
// Example 1 // https://jscomplete.com/repl?j=Sy3QAdKHW function Button (props) {// Returns a DOM element here. For example:return <button type="submit">{props.label}</button>; } // To render the Button component to the browser ReactDOM.render(<Button label="Save" />, mountNode)The curly braces used for the button label are explained below. Don’t worry about them now. ReactDOM will also be explained later, but if you want to test this example and all upcoming code examples, the above render function is what you need.
下面說明用于按鈕標(biāo)簽的花括號(hào)。 現(xiàn)在不用擔(dān)心它們。 ReactDOM也將在后面解釋,但是如果您想測試該示例以及所有即將發(fā)布的代碼示例,則需要上面的render函數(shù)。
The second argument to ReactDOM.render is the destination DOM element which React is going to take over and control. In the jsComplete React Playground, you can just use the special variable mountNode.
ReactDOM.render的第二個(gè)參數(shù)是React將要接管并控制的目標(biāo)DOM元素。 在jsComplete React Playground中 ,您可以僅使用特殊變量mountNode 。
JavaScript REPL and Playground for React.jsTest modern JavaScript and React.js code in the browser without any configurationsjscomplete.com/react
適用于React.jsJavaScript REPL和Playground 無需任何配置即可在瀏覽器中測試現(xiàn)代JavaScript和React.js代碼 jscomplete.com/react
Note the following about Example 1:
請注意以下有關(guān)示例1的內(nèi)容:
- The component name starts with a capital letter. This is required since we will be dealing with a mix of HTML elements and React elements. Lowercase names are reserved for HTML elements. In fact, go ahead and try to name the React component just “button” and see how ReactDOM will ignore the function and renders a regular empty HTML button. 組件名稱以大寫字母開頭。 這是必需的,因?yàn)槲覀儗⑻幚鞨TML元素和React元素的混合。 小寫名稱保留給HTML元素。 實(shí)際上,繼續(xù)嘗試將React組件命名為“ button”,看看ReactDOM如何忽略該函數(shù)并呈現(xiàn)常規(guī)的空HTML按鈕。
Every component receives a list of attributes, just like HTML elements. In React, this list is called props. With a function component, you can name it anything though.
每個(gè)組件都會(huì)收到一個(gè)屬性列表,就像HTML元素一樣。 在React中,此列表稱為props 。 使用功能組件,您可以為其命名。
We weirdly wrote what looks like HTML in the returned output of the Button function component above. This is neither JavaScript nor HTML, and it’s not even React.js. But, it’s so popular that it became the default in React applications. It’s called JSX and it’s a JavaScript extension. JSX is also a compromise! Go ahead and try and return any other HTML element inside the function above and see how they are all supported (for example, return a text input element).
我們在上面的Button函數(shù)組件的返回輸出中怪異地寫了HTML。 這既不是JavaScript也不是HTML,甚至都不是React.js。 但是,它是如此流行,以至于成為了React應(yīng)用程序的默認(rèn)設(shè)置。 它稱為JSX ,是JavaScript擴(kuò)展。 JSX也是一種折衷方案 ! 繼續(xù)嘗試并返回上面函數(shù)內(nèi)的任何其他HTML元素,并查看如何全部支持它們(例如,返回文本輸入元素)。
基本原理2:JSX的作用是什么? (Fundamental 2: What the flux is JSX?)
Example 1 above can be written in pure React.js without JSX as follows:
上面的示例1可以用不帶JSX的純React.js編寫,如下所示:
// Example 2 - React component without JSX // https://jscomplete.com/repl?j=HyiEwoYB- function Button (props) {return React.createElement("button",{ type: "submit" },props.label); } // To use Button, you would do something like ReactDOM.render(React.createElement(Button, { label: "Save" }),mountNode );The createElement function is the main function in the React top-level API. It’s 1 of a total of 8 things in that level that you need to learn. That’s how small the React API is.
createElement函數(shù)是React頂級(jí)API中的主要函數(shù)。 這是您需要學(xué)習(xí)的8項(xiàng)內(nèi)容中的1項(xiàng)。 那就是React API的大小。
Much like the DOM itself having a document.createElement function to create an element specified by a tag name, React’s createElement function is a higher-level function that can do what document.createElement does, but it can also be used to create an element to represent a React component. We did the latter when we used the Button component in Example 2 above.
就像DOM本身具有document.createElement函數(shù)來創(chuàng)建由標(biāo)簽名指定的元素一樣,React的createElement函數(shù)是一個(gè)高級(jí)函數(shù),可以完成document.createElement工作,但是它也可以用于創(chuàng)建元素來代表一個(gè)React組件 當(dāng)我們在上面的示例2中使用Button組件時(shí),我們執(zhí)行了后者。
Unlike document.createElement, React’s createElement accepts a dynamic number of arguments after the second one to represent the children of the created element. So createElement actually creates a tree.
與document.createElement不同,React的createElement在第二個(gè)參數(shù)之后接受動(dòng)態(tài)數(shù)量的參數(shù)來表示所創(chuàng)建元素的子代 。 因此createElement實(shí)際上會(huì)創(chuàng)建一棵樹 。
Here’s an example of that:
這是一個(gè)例子:
// Example 3 - React’s createElement API // https://jscomplete.com/repl?j=r1GNoiFBb const InputForm = React.createElement("form",{ target: "_blank", action: "https://google.com/search" },React.createElement("div", null, "Enter input and click Search"),React.createElement("input", { name: "q", className: "input" }),React.createElement(Button, { label: "Search" }) ); // InputForm uses the Button component, so we need that too: function Button (props) {return React.createElement("button",{ type: "submit" },props.label); } // Then we can use InputForm directly with .render ReactDOM.render(InputForm, mountNode);Note a few things about the example above:
請注意有關(guān)上面的示例的一些注意事項(xiàng):
InputForm is not a React component; it’s just a React element. This is why we used it directly in the ReactDOM.render call and not with <InputForm />.
InputForm不是React組件; 它只是一個(gè)React 元素 。 這就是為什么我們直接在ReactDOM.render調(diào)用中而不是在<InputForm />中使用它的原因。
The React.createElement function accepted multiple arguments after the first two. Its list of arguments starting from the 3rd one comprises the list of children for the created element.
React.createElement函數(shù)在前兩個(gè)之后接受多個(gè)參數(shù)。 它的參數(shù)列表從第3個(gè)開始,包括所創(chuàng)建元素的子級(jí)列表。
We were able to nest React.createElement calls because it’s all JavaScript.
我們能夠嵌套R(shí)eact.createElement調(diào)用,因?yàn)樗鼈兌际荍avaScript。
The second argument to React.createElement can be null or an empty object when no attributes or props are needed for the element.
當(dāng)元素不需要屬性或道具時(shí), React.createElement的第二個(gè)參數(shù)可以為null或?yàn)榭諏ο蟆?
- We can mix HTML element with React elements. 我們可以將HTML元素與React元素混合使用。
React’s API tries to be as close to the DOM API as possible, that’s why we use className instead of class for the input element. Secretly, we all wish the React’s API would become part of the DOM API itself. Because, you know, it’s much much better.
React的API嘗試盡可能地接近DOM API,這就是為什么我們使用className而不是class作為輸入元素的原因。 秘密地,我們都希望React的API成為DOM API本身的一部分。 因?yàn)?#xff0c;這要好得多。
The code above is what the browser understands when you include the React library. The browser does not deal with any JSX business. However, we humans like to see and work with HTML instead of these createElement calls (imagine building a website with just document.createElement, which you can!). This is why the JSX compromise exists. Instead of writing the form above with React.createElement calls, we can write it with a syntax very similar to HTML:
上面的代碼是您包含React庫時(shí)瀏覽器可以理解的內(nèi)容。 該瀏覽器不處理任何JSX業(yè)務(wù)。 但是,我們?nèi)祟愊矚g查看并使用HTML而不是使用這些createElement調(diào)用(想象只使用document.createElement構(gòu)建網(wǎng)站!)。 這就是為什么存在JSX折衷的原因。 不用使用React.createElement調(diào)用編寫上面的表單,我們可以使用非常類似于HTML的語法來編寫它:
// Example 4 - JSX (compare with Example 3) // https://jscomplete.com/repl?j=SJWy3otHW const InputForm =<form target="_blank" action="https://google.com/search"><div>Enter input and click Search</div><input name="q" className="input" /><Button label="Search" /></form>; // InputForm "still" uses the Button component, so we need that too. // Either JSX or normal form would do function Button (props) {// Returns a DOM element here. For example:return <button type="submit">{props.label}</button>; } // Then we can use InputForm directly with .render ReactDOM.render(InputForm, mountNode);Note a few things about the above:
請注意上述幾點(diǎn):
It’s not HTML. For example, we’re still doing className instead of class.
不是HTML。 例如,我們?nèi)栽谑褂胏lassName代替class 。
- We’re still considering what looks like HTML above as JavaScript. See how I added a semicolon at the end. 我們?nèi)栽诳紤]上面看起來像HTMLJavaScript。 看看我如何在末尾添加分號(hào)。
What we wrote above (Example 4) is JSX. Yet, what we took to the browser is the compiled version of it (Example 3). To make that happen, we need to use a pre-processor to convert the JSX version into the React.createElement version.
上面我們寫的(示例4)是JSX。 但是,我們帶給瀏覽器的是它的編譯版本(示例3)。 為此,我們需要使用預(yù)處理器將JSX版本轉(zhuǎn)換為React.createElement版本。
That is JSX. It’s a compromise that allows us to write our React components in a syntax similar to HTML, which is a pretty good deal.
那就是JSX。 這是一個(gè)折衷方案,使我們能夠以類似于HTML的語法編寫React組件,這是非常不錯(cuò)的。
The word “Flux” in the header above was chosen to rhyme, but it’s also the name of a very popular application architecture popularized by Facebook. The most famous implementation of which is Redux. Flux fits the React reactive pattern perfectly.
上面標(biāo)題中的“ Flux”一詞被選為押韻,但這也是Facebook流行的非常流行的應(yīng)用程序體系結(jié)構(gòu)的名稱。 其中最著名的實(shí)現(xiàn)是Redux。 助焊劑非常適合ReactReact模式。
JSX, by the way, can be used on its own. It’s not a React-only thing.
順便說一下,JSX可以單獨(dú)使用。 這不是只做React的事情。
基本原理3:您可以在JSX中的任何位置使用JavaScript表達(dá)式 (Fundamental 3: You can use JavaScript expressions anywhere in JSX)
Inside a JSX section, you can use any JavaScript expression within a pair of curly braces.
在JSX部分中,您可以在一對花括號(hào)內(nèi)使用任何JavaScript表達(dá)式。
// To use it:ReactDOM.render(<RandomValue />, mountNode);// Example 5 - Using JavaScript expressions in JSX // https://jscomplete.com/repl?j=SkNN3oYSW const RandomValue = () => <div>{ Math.floor(Math.random() * 100) }</div>; // To use it: ReactDOM.render(<RandomValue />, mountNode);Any JavaScript expression can go inside those curly braces. This is equivalent to the ${} interpolation syntax in JavaScript template literals.
任何JavaScript表達(dá)式都可以放在這些花括號(hào)內(nèi)。 這等效于JavaScript 模板文字中的${}插值語法。
This is the only constraint inside JSX: only expressions. So, for example, you can’t use a regular if statement, but a ternary expression is ok.
這是JSX內(nèi)部的唯一約束:僅表達(dá)式。 因此,例如,您不能使用正則if語句,但可以使用三元表達(dá)式。
JavaScript variables are also expressions, so when the component receives a list of props (the RandomValue component didn’t, props are optional), you can use these props inside curly braces. We did this in the Button component above (Example 1).
JavaScript變量也是表達(dá)式,因此當(dāng)組件接收到一系列道具時(shí)( RandomValue組件沒有, props是可選的),您可以在花括號(hào)內(nèi)使用這些道具。 我們在上面的Button組件中進(jìn)行了此操作(示例1)。
JavaScript objects are also expressions. Sometimes we use a JavaScript object inside curly braces, which makes it look like double curly braces, but it’s really just an object inside curly braces. One use case of that is to pass a CSS style object to the special style attribute in React:
JavaScript對象也是表達(dá)式。 有時(shí)我們在花括號(hào)內(nèi)使用JavaScript對象,這使其看起來像雙花括號(hào),但實(shí)際上只是花括號(hào)內(nèi)的對象。 一個(gè)用例是將CSS樣式對象傳遞給React中的特殊style屬性:
// Example 6 - An object passed to the special React style prop // https://jscomplete.com/repl?j=S1Kw2sFHb const ErrorDisplay = ({message}) =><div style={ { color: 'red', backgroundColor: 'yellow' } }>{message}</div>; // Use it: ReactDOM.render(<ErrorDisplay message="These aren't the droids you're looking for" />,mountNode );Note how I destructured only the message out of the props argument. Also note how the style attribute above is a special one (again, it’s not HTML, it’s closer to the DOM API). We use an object as the value of the style attribute. That object defines the styles as if we’re doing so with JavaScript (because we are).
請注意我是如何從props參數(shù)中解構(gòu)出消息的。 還要注意上面的style屬性是如何特殊的(同樣,它不是HTML,它更接近DOM API)。 我們使用一個(gè)對象作為style屬性的值。 該對象定義樣式,就像我們使用JavaScript一樣(因?yàn)槭?。
You can even use a React element inside JSX, because that too is an expression. Remember, a React element is essentially a function call:
您甚至可以在JSX中使用React元素,因?yàn)槟且彩且粋€(gè)表達(dá)式。 記住,React元素本質(zhì)上是一個(gè)函數(shù)調(diào)用:
// Example 7 - Using a React element within {} // https://jscomplete.com/repl?j=SkTLpjYr- const MaybeError = ({errorMessage}) =><div>{errorMessage && <ErrorDisplay message={errorMessage} />}</div>;// The MaybeError component uses the ErrorDisplay component: const ErrorDisplay = ({message}) =><div style={ { color: 'red', backgroundColor: 'yellow' } }>{message}</div>; // Now we can use the MaybeError component: ReactDOM.render(<MaybeErrorerrorMessage={Math.random() > 0.5 ? 'Not good' : ''}/>,mountNode );The MaybeError component above would only display the ErrorDisplay component if there is an errorMessage string passed to it and an empty div. React considers {true}, {false}, {undefined}, and {null} to be valid element children, which do not render anything.
如果傳遞了errorMessage字符串和一個(gè)空div ,則上面的MaybeError組件將僅顯示ErrorDisplay組件。 React認(rèn)為{true} , {false} , {undefined}和{null}是有效的元素子元素,它們不會(huì)呈現(xiàn)任何內(nèi)容。
You can also use all of JavaScript functional methods on collections (map, reduce, filter, concat, and so on) inside JSX. Again, because they return expressions:
您還可以在JSX內(nèi)的集合( map , reduce , filter , concat等)上使用所有JavaScript功能方法。 同樣,因?yàn)樗鼈兎祷乇磉_(dá)式:
// Example 8 - Using an array map inside {} // https://jscomplete.com/repl?j=SJ29aiYH- const Doubler = ({value=[1, 2, 3]}) =><div>{value.map(e => e * 2)}</div>; // Use it ReactDOM.render(<Doubler />, mountNode);Note how I gave the value prop a default value above, because it’s all just Javascript. Note also that I outputted an array expression inside the div. React is okay with that; It will place every doubled value in a text node.
請注意,我是如何給value prop設(shè)置上面的默認(rèn)值的,因?yàn)樗鼈內(nèi)际荍avascript。 還要注意,我在div輸出了一個(gè)數(shù)組表達(dá)式。 React對此還可以; 它將每個(gè)雙精度值放置在文本節(jié)點(diǎn)中。
基礎(chǔ)知識(shí)4:您可以使用JavaScript類編寫React組件 (Fundamental 4: You can write React components with JavaScript classes)
Simple function components are great for simple needs, but sometimes we need more. React supports creating components through the JavaScript class syntax as well. Here’s the Button component (in Example 1) written with the class syntax:
簡單的功能組件非常適合簡單的需求,但有時(shí)我們需要更多。 React也支持通過JavaScript類語法創(chuàng)建組件。 這是用類語法編寫的Button組件(在示例1中):
// Example 9 - Creating components using JavaScript classes // https://jscomplete.com/repl?j=ryjk0iKHb class Button extends React.Component {render() {return <button>{this.props.label}</button>;} } // Use it (same syntax) ReactDOM.render(<Button label="Save" />, mountNode);The class syntax is simple. Define a class that extends React.Component (another top-level React API thing that you need to learn). The class defines a single instance function render(), and that render function returns the virtual DOM element. Every time we use the Button class-based component above (for example, by doing <Button ... />), React will instantiate an object from this class-based component and use that object to render a DOM element in the DOM tree.
類語法很簡單。 定義一個(gè)擴(kuò)展React.Component的類(您需要學(xué)習(xí)的另一個(gè)頂級(jí)React API東西)。 該類定義單個(gè)實(shí)例函數(shù)render() ,并且該渲染函數(shù)返回虛擬DOM元素。 每次我們使用上面的基于Button類的組件時(shí)(例如,通過執(zhí)行<Button ... />),React將從該基于類的組件中實(shí)例化一個(gè)對象,并使用該對象在DOM樹中呈現(xiàn)DOM元素。 。
This is the reason why we used this.props.label inside the JSX in the rendered output above. Because every element rendered through a class component gets a special instance property called props that holds all values passed to that element when it was created.
這就是為什么我們在上面呈現(xiàn)的輸出中的JSX中使用this.props.label的原因。 因?yàn)橥ㄟ^類組件呈現(xiàn)的每個(gè)元素都會(huì)獲得一個(gè)稱為props的特殊實(shí)例屬性,該屬性保存創(chuàng)建時(shí)傳遞給該元素的所有值。
Since we have an instance associated with a single use of the component, we can customize that instance as we wish. We can, for example, customize it after it gets constructed by using the regular JavaScript constructor function:
由于我們有一個(gè)與組件的單一使用相關(guān)聯(lián)的實(shí)例,因此我們可以根據(jù)需要自定義該實(shí)例。 例如,我們可以在使用常規(guī)JavaScript constructor函數(shù)構(gòu)造后對其進(jìn)行自定義:
// Example 10 - Customizing a component instance // https://jscomplete.com/repl?j=rko7RsKS- class Button extends React.Component {constructor(props) {super(props);this.id = Date.now();}render() {return <button id={this.id}>{this.props.label}</button>;} } // Use it ReactDOM.render(<Button label="Save" />, mountNode);We can also define class functions and use them anywhere we wish, including inside the returned JSX output:
我們還可以定義類函數(shù),并在希望的任何地方使用它們,包括在返回的JSX輸出內(nèi)部:
// Example 11 — Using class properties // https://jscomplete.com/repl?j=H1YDCoFSb class Button extends React.Component {clickCounter = 0;handleClick = () => {console.log(`Clicked: ${++this.clickCounter}`);};render() {return (<button id={this.id} onClick={this.handleClick}>{this.props.label}</button>);} } // Use it ReactDOM.render(<Button label="Save" />, mountNode);Note a few things about Example 11 above:
請注意上述示例11的一些注意事項(xiàng):
The handleClick function is written using the new proposed class-field syntax in JavaScript. This is still at stage-2, but for many reasons it’s the best option to access the component mounted instance (thanks to arrow functions). But, you need to use a compiler like Babel configured to understand stage-2 (or the class-field syntax) to get the code above to work. The jsComplete REPL has that pre-configured.
handleClick函數(shù)是使用JavaScript中新提議的類字段語法編寫的。 這仍然處于階段2,但是由于許多原因,這是訪問組件安裝的實(shí)例的最佳選擇(由于使用了箭頭功能)。 但是,您需要使用像Babel這樣的編譯器,將其配置為了解Stage-2(或類字段語法),才能使上面的代碼正常工作。 jsComplete REPL已預(yù)先配置。
We’ve also defined the clickCounter instance variables using the same class-field syntax. This allows us to skip using a class constructor call altogether.
我們還使用相同的類字段語法定義了clickCounter實(shí)例變量。 這使我們可以完全跳過使用類構(gòu)造函數(shù)的調(diào)用。
When we specified the handleClick function as the value of the special onClick React attribute, we did not call it. We passed in the reference to the handleClick function. Calling the function on that level is one of the most common mistakes when working with React.
當(dāng)我們將handleClick函數(shù)指定為特殊onClick React屬性的值時(shí),我們沒有調(diào)用它。 我們將引用傳遞給handleClick函數(shù)。 在使用React時(shí),在該級(jí)別上調(diào)用函數(shù)是最常見的錯(cuò)誤之一。
基礎(chǔ)5:React中的事件:兩個(gè)重要區(qū)別 (Fundamental 5: Events in React: Two Important Differences)
When handling events inside React elements, there are two very important differences from the way we do so with the DOM API:
在React元素內(nèi)部處理事件時(shí),與我們使用DOM API的方式有兩個(gè)非常重要的區(qū)別:
All React elements attributes (events included) are named using camelCase, rather than lowercase. It’s onClick, not onclick.
所有React元素屬性(包括事件)都使用camelCase命名,而不是小寫 。 它是onClick ,而不是onclick 。
We pass an actual JavaScript function reference as the event handler, rather than a string. It’s onClick={handleClick}, not onClick="handleClick".
我們傳遞實(shí)際JavaScript函數(shù)引用作為事件處理程序,而不是字符串。 它是onClick={ handleClick } ,而不是onClick=" handleClick" 。
React wraps the DOM event object with an object of its own to optimize the performance of events handling. But inside an event handler, we can still access all methods available on the DOM event object. React passes that wrapped event object to every handle call. For example, to prevent a form from the default submission action, you can do:
React用自己的對象包裝DOM事件對象,以優(yōu)化事件處理的性能。 但是在事件處理程序內(nèi)部,我們?nèi)匀豢梢栽L問DOM事件對象上可用的所有方法。 React將包裝的事件對象傳遞給每個(gè)句柄調(diào)用。 例如,要阻止表單執(zhí)行默認(rèn)的提交操作,可以執(zhí)行以下操作:
// Example 12 - Working with wrapped events // https://jscomplete.com/repl?j=HkIhRoKBb class Form extends React.Component {handleSubmit = (event) => {event.preventDefault();console.log('Form submitted');};render() {return (<form onSubmit={this.handleSubmit}><button type="submit">Submit</button></form>);} } // Use it ReactDOM.render(<Form />, mountNode);基本原理6:每個(gè)React組件都有一個(gè)故事 (Fundamental 6: Every React component has a story)
The following applies to the class component only (those that extend React.Component). Function components have a slightly different story.
以下內(nèi)容僅適用于類組件(那些擴(kuò)展了React.Component )。 功能組件的故事略有不同。
Then, we instruct React to use it somewhere. For example, inside a render call of another component, or with ReactDOM.render.
然后,我們指示React在某處使用它。 例如,在另一個(gè)組件的render調(diào)用中,或在ReactDOM.render 。
Then, React instantiates an element and gives it a set of props that we can access with this.props. Those props are exactly what we passed in step 2 above.
然后,React實(shí)例化一個(gè)元素,并為其提供一組道具 ,我們可以使用this.props訪問。 這些道具正是我們在上面的步驟2中通過的。
Since it’s all JavaScript, the constructor method will be called (if defined). This is the first of what we call: component lifecycle methods.
由于全部使用JavaScript,因此將調(diào)用constructor方法(如果已定義)。 這是我們所謂的第一個(gè): 組件生命周期方法 。
Since this is the first time React is rendering the element, React will communicate with the browser (on our behalf, using the DOM API) to display the element there. This process is commonly known as mounting.
由于這是React首次渲染元素,因此React將與瀏覽器通信(代表我們,使用DOM API)以在其中顯示元素。 此過程通常稱為安裝 。
React then invokes another lifecycle method, called componentDidMount. We can use this method to, for example, do something on the DOM that we now know exists in the browser. Prior to this lifecycle method, the DOM we work with was all virtual.
然后,React調(diào)用另一個(gè)生命周期方法,稱為componentDidMount 。 例如,我們可以使用此方法在DOM上執(zhí)行某些我們現(xiàn)在知道存在于瀏覽器中的操作。 在使用這種生命周期方法之前,我們使用的DOM都是虛擬的。
Some components stories end here. Other components get unmounted from the browser DOM for various reasons. Right before the latter happens, React invokes another lifecycle method, componentWillUnmount.
一些組件的故事到此結(jié)束。 由于各種原因,其他組件也會(huì)從瀏覽器DOM中卸載。 就在后者發(fā)生之前,React調(diào)用了另一個(gè)生命周期方法componentWillUnmount 。
The state of any mounted element might change. The parent of that element might re-render. In either case, the mounted element might receive a different set of props. React magic happens here and we actually start needing React at this point! Prior to this point, we did not need React at all, honestly.
任何已安裝元素的狀態(tài)都可能更改。 該元素的父元素可能會(huì)重新呈現(xiàn)。 在任何一種情況下,已安裝的元素可能會(huì)接收到不同的道具集。 React魔術(shù)在這里發(fā)生,我們此時(shí)實(shí)際上開始需要 React! 在此之前,老實(shí)說,我們根本不需要React。
The story of this component continues, but before it does, we need to understand this state thing that I speak of.
此組件的故事還在繼續(xù),但它之前,我們需要了解這個(gè)國家的事情,我說的。
基本原理7:React組件可以具有私有狀態(tài) (Fundamental 7: React components can have a private state)
The following is also only applicable to class components. Did I mention that some people call presentational-only components dumb?
以下內(nèi)容也僅適用于類組件。 我是否提到有些人稱僅表示組件愚蠢 ?
The state property is a special one in any React class component. React monitors every component state for changes. But for React to do so efficiently, we have to change the state field through another React API thing that we need to learn, this.setState:
state屬性在任何React類組件中都是一個(gè)特殊的屬性。 React監(jiān)視每個(gè)組件狀態(tài)的更改。 但是為了使React有效地做到這一點(diǎn),我們必須通過需要學(xué)習(xí)的另一個(gè)React API事物this.setState來更改狀態(tài)字段:
// Example 13 - the setState API // https://jscomplete.com/repl?j=H1fek2KH- class CounterButton extends React.Component {state = {clickCounter: 0,currentTimestamp: new Date(),};handleClick = () => {this.setState((prevState) => {return { clickCounter: prevState.clickCounter + 1 };});};componentDidMount() {setInterval(() => {this.setState({ currentTimestamp: new Date() })}, 1000);}render() {return (<div><button onClick={this.handleClick}>Click</button><p>Clicked: {this.state.clickCounter}</p><p>Time: {this.state.currentTimestamp.toLocaleString()}</p></div>);} } // Use it ReactDOM.render(<CounterButton />, mountNode);This is the most important example to understand. It will basically complete your fundamental knowledge of the React way. After this example, there are a few other small things that you need to learn, but it’s mostly you and your JavaScript skills from that point.
這是最重要的例子。 它將基本完成您對React方法的基礎(chǔ)知識(shí)。 在此示例之后,還需要學(xué)習(xí)其他一些小知識(shí),但是從那時(shí)起,主要是您和您JavaScript技能。
Let’s walk through Example 13, starting with class fields. It has two of them. The special state field is initialized with an object that holds a clickCounter that starts with 0, and a currentTimestamp that starts with new Date().
讓我們從類字段開始講解示例13。 它有兩個(gè)。 特殊state字段由一個(gè)對象初始化,該對象包含一個(gè)以0開頭的clickCounter和一個(gè)以new Date()開頭的currentTimestamp 。
The second class field is a handleClick function, which we passed to the onClick event for the button element inside the render method. The handleClick method modifies this component instance state using setState. Take notice of that.
第二個(gè)類字段是handleClick函數(shù),我們將其傳遞給render方法內(nèi)button元素的onClick事件。 handleClick方法使用setState修改此組件實(shí)例狀態(tài)。 注意這一點(diǎn)。
The other place we’re modifying the state is inside an interval timer that we started inside the componentDidMount lifecycle method. It ticks every second and executes another call to this.setState.
我們要修改狀態(tài)的另一個(gè)地方是在componentDidMount生命周期方法內(nèi)啟動(dòng)的間隔計(jì)時(shí)器內(nèi)。 它每秒滴答this.setState并執(zhí)行對this.setState另一個(gè)調(diào)用。
In the render method, we used the two properties we have on the state with a normal read syntax. There is no special API for that.
在render方法中,我們使用正常讀取語法在狀態(tài)上使用了兩個(gè)屬性。 對此沒有特殊的API。
Now, notice that we updated the state using two different ways:
現(xiàn)在,請注意,我們使用兩種不同的方式來更新狀態(tài):
By passing a function that returned an object. We did that inside the handleClick function.
通過傳遞返回對象的函數(shù)。 我們在handleClick函數(shù)中進(jìn)行了此操作。
Both ways are acceptable, but the first one is preferred when you read and write to the state at the same time (which we do). Inside the interval callback, we’re only writing to the state and not reading it. When in doubt, always use the first function-as-argument syntax. It’s safer with race conditions because setState should always be treated as an asynchronous method.
兩種方法都可以接受,但是當(dāng)您同時(shí)讀取和寫入狀態(tài)時(shí)(我們這樣做),首選第一種方法。 在時(shí)間間隔回調(diào)中,我們僅寫入狀態(tài),而不讀取狀態(tài)。 如有疑問,請始終使用第一個(gè)函數(shù)自變量語法。 在競爭條件下更安全,因?yàn)閟etState應(yīng)該始終被視為異步方法。
How do we update the state? We return an object with the new value of what we want to update. Notice how in both calls to setState, we’re only passing one property from the state field and not both. This is completely okay because setState actually merges what you pass it (the returned value of the function argument) with the existing state. So, not specifying a property while calling setState means that we wish to not change that property (but not delete it).
我們?nèi)绾胃聽顟B(tài)? 我們返回一個(gè)具有我們要更新的新值的對象。 請注意,在兩次調(diào)用setState ,我們僅從狀態(tài)字段傳遞一個(gè)屬性,而不是兩者。 這完全可以,因?yàn)閟etState實(shí)際上將您傳遞的內(nèi)容(函數(shù)參數(shù)的返回值)與現(xiàn)有狀態(tài)合并。 因此,在調(diào)用setState未指定屬性意味著我們希望不更改該屬性(但不要?jiǎng)h除它)。
基礎(chǔ)8:React會(huì)做出React (Fundamental 8: React will react)
React gets its name from the fact that it reacts to state changes (although not reactively, but on a schedule). There was a joke that React should have been named Schedule!
React之所以得名,是因?yàn)樗鼘顟B(tài)更改做出了React (盡管不是被動(dòng)的,而是按計(jì)劃進(jìn)行的)。 開個(gè)玩笑說React應(yīng)該被命名為Schedule !
However, what we witness with the naked eye when the state of any component gets updated is that React reacts to that update and automatically reflects the update in the browser DOM (if needed).
但是,當(dāng)任何組件的狀態(tài)被更新時(shí),我們用肉眼看到的是,React對更新進(jìn)行React,并自動(dòng)在瀏覽器DOM中反映該更新(如果需要)。
Think of the render function’s input as both:
將渲染函數(shù)的輸入都視為:
- The props that get passed by the parent 父母通過的道具
- The internal private state that can be updated anytime 可以隨時(shí)更新的內(nèi)部私有狀態(tài)
When the input of the render function changes, its output might change.
當(dāng)渲染函數(shù)的輸入更改時(shí),其輸出可能更改。
React keeps a record of the history of renders and when it sees that one render is different than the previous one, it’ll compute the difference between them and efficiently translate it into actual DOM operations that get executed in the DOM.
React記錄了渲染的歷史記錄,當(dāng)發(fā)現(xiàn)一個(gè)渲染與上一個(gè)渲染不同時(shí),React將計(jì)算它們之間的差異,并將其有效地轉(zhuǎn)換為在DOM中執(zhí)行的實(shí)際DOM操作。
基礎(chǔ)知識(shí)9:React是您的代理 (Fundamental 9: React is your agent)
You can think of React as the agent we hired to communicate with the browser. Take the current timestamp display above as an example. Instead of us manually going to the browser and invoking DOM API operations to find and update the p#timestamp element every second, we just changed a property on the state of the component and React did its job of communicating with the browser on our behalf. I believe this is the true reason why React is popular. We hate talking to Mr. Browser (and the so many dialects of the DOM language that it speaks) and React volunteered to do all the talking for us, for free.
您可以將React視為我們雇用的與瀏覽器進(jìn)行通信的代理。 以上面的當(dāng)前時(shí)間戳顯示為例。 代替我們手動(dòng)去瀏覽器并每秒調(diào)用DOM API操作來查找和更新p#timestamp元素,我們只是更改了組件狀態(tài)的屬性,而React代表我們與瀏覽器進(jìn)行通信。 我相信這是React受歡迎的真正原因。 我們討厭與Browser先生(以及它所講的DOM語言的眾多方言)交談,而React自愿為我們免費(fèi)進(jìn)行所有交談。
基礎(chǔ)知識(shí)10:每個(gè)React組件都有一個(gè)故事(第2部分) (Fundamental 10: Every React component has a story (part 2))
Now that we know about the state of a component and how when that state changes some magic happens, let’s learn the last few concepts about that process.
既然我們已經(jīng)知道了組件的狀態(tài)以及該狀態(tài)如何發(fā)生變化,那么就會(huì)發(fā)生一些不可思議的事情,讓我們學(xué)習(xí)有關(guān)該過程的最后幾個(gè)概念。
If the latter happens, React invokes another lifecycle method, componentWillReceiveProps.
如果發(fā)生后者,React將調(diào)用另一個(gè)生命周期方法componentWillReceiveProps 。
If either the state object or the passed-in props are changed, React has an important decision to do. Should the component be updated in the DOM? This is why it invokes another important lifecycle method here, shouldComponentUpdate. This method is an actual question, so if you need to customize or optimize the render process on your own, you have to answer that question by returning either true or false.
如果更改了狀態(tài)對象或傳入的道具,React將做出重要決定。 是否應(yīng)在DOM中更新組件? 這就是為什么它在這里調(diào)用另一個(gè)重要的生命周期方法shouldComponentUpdate 。 這個(gè)方法是一個(gè)實(shí)際的問題,所以如果你需要定制或自己進(jìn)行優(yōu)化渲染過程中,可以通過返回true 或 false來回答這個(gè)問題。
If there is no custom shouldComponentUpdate specified, React defaults to a very smart thing that’s actually good enough in most situations.
如果沒有指定自定義的shouldComponentUpdate ,React默認(rèn)會(huì)是一個(gè)非常聰明的東西,實(shí)際上在大多數(shù)情況下已經(jīng)足夠了。
First, React invokes another lifecycle method at this point, componentWillUpdate. React will then compute the new rendered output and compare it with the last rendered output.
首先,React此時(shí)會(huì)調(diào)用另一個(gè)生命周期方法componentWillUpdate 。 然后,React將計(jì)算新的渲染輸出并將其與最后渲染的輸出進(jìn)行比較。
In any case, since an update process happened anyway (even if the output was exactly the same), React invokes the final lifecycle method, componentDidUpdate.
無論如何,由于無論如何都會(huì)發(fā)生更新過程(即使輸出完全相同),因此React會(huì)調(diào)用最終的生命周期方法componentDidUpdate 。
Lifecycle methods are actually escape hatches. If you’re not doing anything special, you can create full applications without them. They’re very handy for analyzing what is going on in the application and for further optimizing the performance of React updates.
生命周期方法實(shí)際上是逃生艙口。 如果您沒有做任何特別的事情,則可以在沒有它們的情況下創(chuàng)建完整的應(yīng)用程序。 對于分析應(yīng)用程序中發(fā)生的事情以及進(jìn)一步優(yōu)化React更新的性能,它們非常方便。
That’s it. Believe it or not, with what you learned above (or parts of it, really), you can start creating some interesting React applications. If you’re hungry for more, check out my Learn React.js by Building Games book!
而已。 信不信由你,使用上面的知識(shí)(或部分知識(shí)),您可以開始創(chuàng)建一些有趣的React應(yīng)用程序。 如果您渴望獲得更多,請查看我的《 Building Games學(xué)習(xí)Learn.js》一書!
Thanks to the many readers who reviewed and improved this article, ?ukasz Szewczak, Tim Broyles, Kyle Holden, Robert Axelse, Bruce Lane, Irvin Waldman, and Amie Wilt.
?ukaszSzewczak,Tim Broyles,Kyle Holden,Robert Axelse,Bruce Lane,Irvin Waldman和Amie Wilt感謝許多閱讀和改進(jìn)本文的讀者。
Learning React or Node? Checkout my books:
學(xué)習(xí)React還是Node? 結(jié)帳我的書:
Learn React.js by Building Games
通過構(gòu)建游戲?qū)W習(xí)React.js
Node.js Beyond the Basics
超越基礎(chǔ)的Node.js
翻譯自: https://www.freecodecamp.org/news/all-the-fundamental-react-js-concepts-jammed-into-this-single-medium-article-c83f9b53eac2/
總結(jié)
以上是生活随笔為你收集整理的撰写本文的所有基本React.js概念的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么经常梦到死去的父亲
- 下一篇: 创建外部快照_快照事件:现在如何仅通过拍