轉(zhuǎn)譯自:https://www.robinwieruch.de/react-function-component
本文在已發(fā)布在GitHub(https://github.com/clxering/Technical-Articles-Collection/blob/master/React/React-Function-Components.md)歡迎糾錯訂正
React Function Components -- also known as React Functional Components -- are the status quo of writing modern React applications. In the past, there have been various React Component Types, but with the introduction of React Hooks it's possible to write your entire application with just functions as React components.
React Function Components(也稱為 React 函數(shù)組件)是現(xiàn)代 React 應(yīng)用程序的組成模塊。在過去昧廷,有多種 React 組件類型切黔,但是隨著 React 鉤子 的引入阅束,僅用 React 函數(shù)組件來編寫整個應(yīng)用程序成為可能媒熊。
This in-depth guide shows you everything about React Function Components -- which are basically just JavaScript Functions being React Components which return JSX (React's Syntax) -- so that after you have read this tutorial you should be well prepared to implement modern React applications with them.
這個深入的指南向你展示了 React 函數(shù)組件的所有內(nèi)容(基于返回 JSX (React 語法)的 React 組件的 JavaScript 函數(shù)),因此习绢,在閱讀本教程之后蝎土,你應(yīng)該做好充分準(zhǔn)備,用它們實(shí)現(xiàn)現(xiàn)代的 React 應(yīng)用程序阵面。
Note: There are several synonyms for this kind of component in React. You may have seen different variations such as "React Function only Component" or "React Component as Function".
注意:React 中有幾種關(guān)于此類組件的同義詞轻局。你可能見過不同的變化,如 React Function only Component 或 React Component as Function
Table of Contents(目錄列表)
- React Function Component Example(函數(shù)組件的例子)
- React Function Component: props(函數(shù)組件的 props)
- React Arrow Function Component(React 的箭頭函數(shù)組件)
- React Stateless Function Component(React 的無狀態(tài)函數(shù)組件)
- React Function Component: state(React 函數(shù)組件之:狀態(tài))
- React Function Component: Event Handler(React 函數(shù)組件之:事件處理程序)
- React Function Component: Callback Function(React 函數(shù)組件之:回調(diào)函數(shù))
- React Function Component: Lifecycle(React 函數(shù)組件之生命周期)
- Pure React Function Component(純 React 函數(shù)組件)
- React Function Component: Export and Import(React 函數(shù)組件之:Export 和 Import)
- React Function Component: ref(React 函數(shù)組件之:ref)
- React Function Component: PropTypes(React 函數(shù)組件之:PropTypes)
- React Function Component: TypeScript(React 函數(shù)組件之:TypeScript)
- React Function Component vs Class Component(React 的函數(shù)組件和類組件)
React Function Component Example(函數(shù)組件的例子)
Let's start with a simple example of a Functional Component in React defined as App which returns JSX:
讓我們從一個簡單例子開始样刷,它定義了一個 App 函數(shù)組件仑扑,并返回 JSX:
import React from 'react';
function App() {
const greeting = 'Hello Function Component!';
return <h1>{greeting}</h1>;
}
export default App;
That's already the essential React Function Component Syntax. The definition of the component happens with just a JavaScript Function which has to return JSX -- React's syntax for defining a mix of HTML and JavaScript whereas the JavaScript is used with curly braces within the HTML. In our case, we render a variable called greeting, which is defined in the component's function body, and is returned as HTML headline in JSX.
這已經(jīng)是基本的 React 函數(shù)組件語法了。組件的定義只需要一個 JavaScript 函數(shù)置鼻,該函數(shù)必須返回 JSX(React 用于定義混合 HTML 和 JavaScript 的語法镇饮,而 JavaScript 在 HTML 中使用花括號)。在例子中箕母,我們渲染了一個名為 greeting 的變量储藐,它在組件的函數(shù)體中定義,并在 JSX 中作為 HTML 標(biāo)題返回嘶是。
Note: If you are familiar with React Class Components, you may have noticed that a Functional Component is a React Component without render function. Everything defined in the function's body is the render function which returns JSX in the end.
注意:如果你熟悉 React 類組件钙勃,你可能已經(jīng)注意到函數(shù)組件是沒有 render 函數(shù)的 React 組件。在函數(shù)體中定義的所有內(nèi)容都是 render 函數(shù)聂喇,該函數(shù)最后返回 JSX辖源。
Now, if you want to render a React Component inside a Function Component, you define another component and render it as HTML element with JSX within the other component's body:
如果你想在函數(shù)組件中渲染一個 React 組件,你需要定義一個新組件并將其渲染為 HTML 元素授帕,而 JSX 則在新組件的主體中:
import React from 'react';
function App() {
return <Headline />;
}
function Headline() {
const greeting = 'Hello Function Component!';
return <h1>{greeting}</h1>;
}
export default App;
Basically you have a function as Child Component now. Defining React Components and rendering them within each other makes Composition in React possible. You can decide where to render a component and how to render it.
你現(xiàn)在有了一個函數(shù)作為子組件同木。定義 React 組件并互相渲染,使得 在 React 中組合 成為可能跛十。你可以決定在何處渲染組件以及如何渲染它彤路。
React Function Component: props(函數(shù)組件的 props)
Let's learn about a React Function Component with props. In React, props are used to pass information from component to component. If you don't know about props in React, cross-read the linked article. Essentially props in React are always passed down the component tree:
讓我們學(xué)習(xí)一下 React 函數(shù)組件的 props。在 React 中芥映,props 用于在組件之間傳遞信息洲尊。如果你不知道 React 里的 props远豺,可交叉閱讀相關(guān)文章。本質(zhì)上坞嘀,React 中的 props 總是沿著組件樹向下傳遞:
import React from 'react';
function App() {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
}
function Headline(props) {
return <h1>{props.value}</h1>;
}
export default App;
Props are the React Function Component's parameters. Whereas the component can stay generic, we decide from the outside what it should render (or how it should behave). When rendering a component (e.g. Headline in App component), you can pass props as HTML attributes to the component. Then in the Function Component the props object is available as argument in the function signature.
props 是 React 函數(shù)組件的參數(shù)躯护。雖然組件可以保持通用,但是我們從外部決定它應(yīng)該渲染什么(或者它應(yīng)該有什么行為)丽涩。當(dāng)渲染一個組件時(例如在 App 組件中的 Headline)棺滞,你可以將 props 作為 HTML 屬性傳遞給組件。在函數(shù)組件中矢渊,props 對象在函數(shù)簽名中是可用的參數(shù)继准。
Since props are always coming as object, and most often you need to extract the information from the props anyway, JavaScript object destructuring comes in handy. You can directly use it in the function signature for the props object:
由于 props 總是以對象形式出現(xiàn),而且大多數(shù)情況下無論如何都需要從 props 中提取信息矮男,因此 JavaScript 對象解構(gòu) 就派上用場了移必。你可以直接在 props 對象的函數(shù)簽名中使用:
import React from 'react';
function App() {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
}
function Headline({ value }) {
return <h1>{value}</h1>;
}
export default App;
Note: If you forget the JavaScript destructuring and just access props from the component's function signature like function Headline(value1, value2) { ... }
, you may see a "props undefined"-messages. It doesn't work this way, because props are always accessible as first argument of the function and can be destructured from there: function Headline({ value1, value2 }) { ... }
.
注意:如果你忘記了 JavaScript 的解構(gòu),而只是從組件的函數(shù)簽名毡鉴,如 function Headline(value1, value2) { ... }
訪問 props崔泵,你可能會看到一個 "props undefined" 的消息。它不是這樣工作的猪瞬,因?yàn)?props 總是作為函數(shù)的第一個參數(shù)憎瘸,可以從函數(shù)簽名那里解構(gòu):function Headline({ value1, value2 }) { ... }
。
If you want to learn more tricks and tips about React props, again check out the linked article from the beginning of this section. There you will learn about cases where you don't want to destructure your props and simply pass them to the next child component with the ...syntax known as spread operator.
如果你想了解更多關(guān)于 React props 的技巧和提示撑螺,請再次查看本節(jié)開頭的鏈接文章含思。在文章中,你將了解不對 props 解構(gòu)的情況甘晤,并簡單地用帶有 …
的語法將它們傳遞給下一個子組件,這種語法稱為擴(kuò)展運(yùn)算符饲做。
React Arrow Function Component(React 的箭頭函數(shù)組件)
With the introduction of JavaScript ES6, new coding concepts were introduced to JavaScript and therefore to React. For instance, a JavaScript function can be expressed as lambda (arrow function). That's why a Function Component is sometimes called Arrow Function Components (or maybe also Lambda Function Component). Let's see our refactored React Component with an Arrow Function:
隨著 JavaScript ES6 的引入线婚,新的編碼概念被引入到 JavaScript 中,React 也不例外盆均。例如塞弊,一個 JavaScript 函數(shù)可以表示為 lambda 箭頭函數(shù)。這就是為什么一個函數(shù)組件有時被稱為箭頭函數(shù)組件(或者 Lambda 函數(shù)組件)泪姨。讓我們看看用箭頭函數(shù)重構(gòu)的 React 組件:
import React from 'react';
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
};
const Headline = ({ value }) => {
return <h1>{value}</h1>;
};
export default App;
Both React Arrow Function Components use a function block body now. However, the second component can be made more lightweight with a concise body for the function, because it only returns the output of the component without doing something else in between. When leaving away the curly braces, the explicit return becomes an implicit return and can be left out as well:
兩個 React 箭頭函數(shù)組件現(xiàn)在都使用一個函數(shù)塊體游沿。但是,第二個組件可以用一個簡潔的函數(shù)體使其更輕量級肮砾,因?yàn)樗环祷亟M件的輸出诀黍,而不做其他事情。當(dāng)去掉花括號時仗处,顯式 return 變成隱式 return眯勾,也可以省略:
import React from 'react';
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
};
const Headline = ({ value }) =>
<h1>{value}</h1>;
export default App;
When using arrow functions for React components, nothing changes for the props. They are still accessible as arguments as before. It's a React Function Component with ES6 Functions expressed as arrows instead of ES5 Functions which are the more default way of expressing functions in JS.
當(dāng) React 組件使用箭頭函數(shù)時枣宫,props 不會發(fā)生任何變化。它們?nèi)匀豢梢宰鳛閰?shù)使用吃环。它是一個用箭頭表示 ES6 函數(shù)的 React 函數(shù)組件也颤,而不是在 JS 中表示函數(shù)的默認(rèn)方式 ES5 函數(shù)。
Note: If you run into a "React Component Arrow Function Unexpected Token" error, make sure that JavaScript ES6 is available for your React application. Normally when using create-react-app this should be given, otherwise, if you set up the project yourself, Babel is enabling ES6 and beyond features for your React application.
注意:如果遇到 React Component Arrow Function Unexpected Token 錯誤郁轻,請確保 React 應(yīng)用程序可用 JavaScript ES6翅娶。通常情況下,當(dāng)使用 create-react-app 時好唯,應(yīng)該確認(rèn)這個選項(xiàng)故觅,否則,如果你自己設(shè)置項(xiàng)目渠啊,Babel 將為你的 React 應(yīng)用程序啟用 ES6 和更多功能输吏。
React Stateless Function Component(React 的無狀態(tài)函數(shù)組件)
Every component we have seen so far can be called Stateless Function Component. They just receive an input as props and return an output as JSX: (props) => JSX
. The input, only if available in form of props, shapes the rendered output. These kind of components don't manage state and don't have any side-effects (e.g. accessing the browser's local storage). People call them Functional Stateless Components, because they are stateless and expressed by a function. However, React Hooks made it possible to have state in Function Components.
到目前為止,我們看到的每個組件都可以稱為無狀態(tài)函數(shù)組件替蛉。它們只是接收一個 props 的輸入贯溅,并返回一個 JSX:(props) => JSX
作為輸出。輸入只能以 props 的形式提供給輸出渲染躲查。這些組件不管理狀態(tài)它浅,也沒有任何副作用(例如訪問瀏覽器的本地存儲)。人們稱它們?yōu)闊o狀態(tài)函數(shù)組件镣煮,因?yàn)樗鼈兪菬o狀態(tài)的姐霍,并由函數(shù)表示。但是典唇,React 鉤子使得函數(shù)組件中有狀態(tài)成為可能镊折。
React Function Component: state(React 函數(shù)組件之:狀態(tài))
React Hooks made it possible to use state (and side-effects) in Function Components. Finally we can create a React Function Component with state! Let's say we moved all logic to our other Function Component and don't pass any props to it:
React 鉤子使得在函數(shù)組件中使用狀態(tài)(和副作用)成為可能。最后介衔,我們可以創(chuàng)建一個有狀態(tài)的 React 函數(shù)組件恨胚!我們把所有的邏輯都移到了另一個函數(shù)組件上,并且沒有給它傳遞任何 props:
import React from 'react';
const App = () => {
return <Headline />;
};
const Headline = () => {
const greeting = 'Hello Function Component!';
return <h1>{greeting}</h1>;
};
export default App;
So far, a user of this application has no way of interacting with the application and thus no way of changing the greeting variable. The application is static and not interactive at all. State is what makes React components interactive; and exciting as well. A React Hook helps us to accomplish it:
到目前為止炎咖,此應(yīng)用程序的用戶還無法與應(yīng)用程序交互赃泡,因此無法更改 greeting 變量。應(yīng)用程序是靜態(tài)的乘盼,完全沒有交互性升熊。狀態(tài)使 React 組件具有交互性;也很令人興奮绸栅。React Hook 幫助我們完成它:
import React, { useState } from 'react';
const App = () => {
return <Headline />;
};
const Headline = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
return <h1>{greeting}</h1>;
};
export default App;
The useState hook takes an initial state as parameter and returns an array which holds the current state as first item and a function to change the state as second item. We are using JavaScript array destructuring to access both items with a shorthand expression. In addition, the destructuring let's us name the variables ourselves.
useState 鉤子將初始狀態(tài)作為參數(shù)级野,并返回一個數(shù)組,其中當(dāng)前狀態(tài)是第一項(xiàng)阴幌,更改狀態(tài)的函數(shù)是第二項(xiàng)勺阐。我們正在使用 JavaScript 數(shù)組解構(gòu) 來訪問這兩個項(xiàng)與一個縮寫表達(dá)式卷中。另外,解構(gòu)還可以讓我們自己給變量命名渊抽。
Let's add an input field to change the state with the setGreeting()
function:
讓我們添加一個 input field 來改變 setGreeting()
函數(shù)的狀態(tài):
import React, { useState } from 'react';
const App = () => {
return <Headline />;
};
const Headline = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
return (
<div>
<h1>{greeting}</h1>
<input
type="text"
value={greeting}
onChange={event => setGreeting(event.target.value)}
/>
</div>
);
};
export default App;
By providing an event handler to the input field, we are able to do something with a callback function when the input field changes its value. As argument of the callback function we receive a synthetic React event which holds the current value of the input field. This value is ultimately used to set the new state for the Function Component with an inline arrow function. We will see later how to extract this function from there.
通過向 input field 提供事件處理程序蟆豫,我們可以在 input field 更改其值時使用回調(diào)函數(shù)來完成某些事情。作為回調(diào)函數(shù)的參數(shù)懒闷,我們接收一個保存 input field 當(dāng)前值的 synthetic React 事件十减。此值最終用于設(shè)置帶有內(nèi)聯(lián)箭頭函數(shù)的函數(shù)組件的新狀態(tài)。稍后我們將看到如何從那里提取這個函數(shù)愤估。
Note: The input field receives the value of the component state too, because you want to control the state (value) of the input field and don't let the native HTML element's internal state take over. Doing it this way, the component has become a controlled component.
注意:input field 也接收組件狀態(tài)的值帮辟,因?yàn)槟阆M刂戚斎胱侄蔚臓顟B(tài)(值),而不讓本機(jī) HTML 元素的內(nèi)部狀態(tài)接管玩焰。這樣做由驹,組件就變成了受控組件。
As you have seen, React Hooks enable us to use state in React (Arrow) Function Components. Whereas you would have used a setState method to write state in a Class Component, you can use the useState hook to write state in a Function Component.
如你所見昔园,React 鉤子使我們能夠在 React(箭頭)函數(shù)組件中使用狀態(tài)蔓榄。雖然可以使用 setState 方法在類組件中寫入狀態(tài),但是可以使用 useState 鉤子在函數(shù)組件中寫入狀態(tài)默刚。
Note: If you want to use React's Context in Function Components, check out React's Context Hook called useContext for reading from React's Context in a component.
注意:如果你想在函數(shù)組件中使用 React 的上下文甥郑,請查看 React 的上下文鉤子 useContext,以便從組件中的 React 上下文中讀取內(nèi)容荤西。
React Function Component: Event Handler(React 函數(shù)組件之:事件處理程序)
In the previous example you have used an onChange event handler for the input field. That's appropriate, because you want to be notified every time the internal value of the input field has changed. In the case of other HTML form elements, you have several other React event handlers at your disposal such as onClick, onMouseDown, and onBlur.
在前面的示例中澜搅,你已經(jīng)為 input field 使用了 onChange 事件處理程序。這是恰當(dāng)?shù)男靶浚驗(yàn)槟阆M诿看?input field 的內(nèi)部值發(fā)生更改時都得到通知勉躺。對于其他 HTML 表單元素,你可以使用其他幾個 React 事件處理程序秃流,如 onClick赂蕴、onMouseDown 和 onBlur。
Note: The onChange event handler is only one of the handlers for HTML form elements. For instance, a button would offer an onClick event handler to react on click events.
注意:onChange 事件處理程序只是 HTML 表單元素的處理程序之一舶胀。例如,按鈕將提供一個 onClick 事件處理程序來對單擊事件作出反應(yīng)碧注。
So far, we have used an arrow function to inline the event handler for out input field. What about extracting it as standalone function inside the component? It would become a named function then:
到目前為止嚣伐,我們已經(jīng)使用了一個箭頭函數(shù)來內(nèi)聯(lián) input field 的事件處理程序,并影響輸出萍丐。將它作為獨(dú)立的函數(shù)提取到組件中呢轩端?它將成為一個具名函數(shù):
import React, { useState } from 'react';
const App = () => {
return <Headline />;
};
const Headline = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
const handleChange = event => setGreeting(event.target.value);
return (
<div>
<h1>{greeting}</h1>
<input type="text" value={greeting} onChange={handleChange} />
</div>
);
};
export default App;
We have used an arrow function to define the function within the component. If you have used class methods in React Class Components before, this way of defining functions inside a React Function Component is the equivalent. You could call it the "React Function Component Methods"-equivalent to class components. You can create or add as many functions inside the Functional Component as you want to act as explicit event handlers or to encapsulate other business logic.
我們使用了一個箭頭函數(shù)來定義組件中的函數(shù)。如果你以前在 React 類組件中使用過類方法逝变,那么在 React 函數(shù)組件中定義函數(shù)的這種方法是等效的基茵。你可以稱之為「React 函數(shù)組件方法」(相當(dāng)于類組件)奋构。你可以在函數(shù)組件中創(chuàng)建或添加盡可能多的函數(shù),以充當(dāng)顯式事件處理程序或封裝其他業(yè)務(wù)邏輯拱层。
React Function Component: Callback Function(React 函數(shù)組件之:回調(diào)函數(shù))
Everything happens in our Child Function Component. There are no props passed to it, even though you have seen before how a string variable for the greeting can be passed from the Parent Component to the Child Component. Is it possible to pass a function to a component as prop as well? Somehow it must be possible to call a component function from the outside! Let's see how this works:
一切都在我們的子函數(shù)組件中發(fā)生弥臼。沒有向它傳遞任何 props,即使你以前已經(jīng)看到了如何將用于 greeting 的字符串變量從父組件傳遞到子組件根灯。有可能將一個函數(shù)作為 props 傳遞給一個組件嗎径缅?無論如何,必須能夠從外部調(diào)用組件函數(shù)烙肺!讓我們看看它是如何工作的:
import React, { useState } from 'react';
const App = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
const handleChange = event => setGreeting(event.target.value);
return (
<Headline headline={greeting} onChangeHeadline={handleChange} />
);
};
const Headline = ({ headline, onChangeHeadline }) => (
<div>
<h1>{headline}</h1>
<input type="text" value={headline} onChange={onChangeHeadline} />
</div>
);
export default App;
That's all to it. You can pass a function to a Child Component and handle what happens up in the Parent Component. You could also execute something in between in the Child Component (Headline component) for the onChangeHeadline
function -- like trimming the value -- to add extra functionality inside the Child Component. That's how you would be able to call a Child Component's function from a Parent Component.
僅此而已纳猪。可以將函數(shù)傳遞給子組件并處理父組件中發(fā)生的事情桃笙。你還可以在子組件(Headline 組件)中為 onChangeHeadline
函數(shù)執(zhí)行一些操作(比如調(diào)整值)氏堤,以在子組件中添加額外的功能。這就是如何從父組件調(diào)用子組件的函數(shù)搏明。
Let's take this example one step further by introducing a Sibling Component for the Headline component. It could be an abstract Input component:
讓我們通過為 Headline 組件引入一個 Sibling 組件來進(jìn)一步研究這個示例鼠锈。它可以是一個抽象的 Input 組件:
import React, { useState } from 'react';
const App = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
const handleChange = event => setGreeting(event.target.value);
return (
<div>
<Headline headline={greeting} />
<Input value={greeting} onChangeInput={handleChange}>
Set Greeting:
</Input>
</div>
);
};
const Headline = ({ headline }) => <h1>{headline}</h1>;
const Input = ({ value, onChangeInput, children }) => (
<label>
{children}
<input type="text" value={value} onChange={onChangeInput} />
</label>
);
export default App;
I find this is a perfect yet minimal example to illustrate how to pass functions between components as props; and more importantly how to share a function between components. You have one Parent Component which manages the logic and two Child Components -- which are siblings -- that receive props. These props can always include a callback function to call a function in another component. Basically that's how it's possible to call a function in different components in React.
我發(fā)現(xiàn)這是一個完美而又簡單的例子,它演示了如何在組件之間傳遞函數(shù)熏瞄;更重要的是如何在組件之間共享一個函數(shù)脚祟。你有一個管理邏輯的父組件和兩個接收 props 的子組件(它們是兄弟組件)。這些支持總是可以包含一個回調(diào)函數(shù)來調(diào)用另一個組件中的函數(shù)强饮∮勺溃基本上這就是在 React 中調(diào)用不同組件中的函數(shù)的方法。
Override Component Function with React(覆蓋 React 組件)
It's shouldn't happen often, but I have heard people asking me this question. How would you override a component's function? You need to take the same approach as for overriding any other passed prop to a component by giving it a default value:
這種情況不應(yīng)該經(jīng)常發(fā)生邮丰,但是有人問我這個問題行您。如何覆蓋組件的函數(shù)?你需要采取相同的方法覆蓋任何其他通過的 props 組件給它一個默認(rèn)值:
import React from 'react';
const App = () => {
const sayHello = () => console.log('Hello');
return <Button handleClick={sayHello} />;
};
const Button = ({ handleClick }) => {
const sayDefault = () => console.log('Default');
const onClick = handleClick || sayDefault;
return (
<button type="button" onClick={onClick}>
Button
</button>
);
};
export default App;
You can assign the default value in the function signature for the destructuring as well:
你也可以在函數(shù)簽名中為解構(gòu)指定默認(rèn)值:
import React from 'react';
const App = () => {
const sayHello = () => console.log('Hello');
return <Button handleClick={sayHello} />;
};
const Button = ({ handleClick = () => console.log('Default') }) => (
<button type="button" onClick={handleClick}>
Button
</button>
);
export default App;
You can also give a React Function Component default props -- which is another alternative:
你也可以給一個 React 函數(shù)組件默認(rèn)的 props(這是另一種選擇):
import React from 'react';
const App = () => {
const sayHello = () => console.log('Hello');
return <Button handleClick={sayHello} />;
};
const Button = ({ handleClick }) => (
<button type="button" onClick={handleClick}>
Button
</button>
);
Button.defaultProps = {
handleClick: () => console.log('Default'),
};
export default App;
All of these approaches can be used to define default props (in this case a default function), to be able to override it later from the outside by passing an explicit prop (e.g. function) to the component.
所有這些方法都可以用來定義默認(rèn)的 props(在本例中是一個默認(rèn)的函數(shù))剪廉,以便以后通過向組件傳遞一個顯式的 props(例如函數(shù))來從外部覆蓋它娃循。
Async Function in Component with React(在 React 組件的異步函數(shù))
Another special case may be an async function in a React component. But there is nothing special about it, because it doesn't matter if the function is asynchronously executed or not:
另一種特殊情況可能是 React 組件中的異步函數(shù)。但是它沒有什么特別之處斗蒋,因?yàn)樗c函數(shù)是否異步執(zhí)行無關(guān):
import React from 'react';
const App = () => {
const sayHello = () =>
setTimeout(() => console.log('Hello'), 1000);
return <Button handleClick={sayHello} />;
};
const Button = ({ handleClick }) => (
<button type="button" onClick={handleClick}>
Button
</button>
);
export default App;
The function executes delayed without any further instructions from your side within the component. The component will also rerender asynchronously in case props or state have changed. Take the following code as example to see how we set state with a artificial delay by using setTimeout
:
該函數(shù)延遲執(zhí)行捌斧,沒有來自組件內(nèi)部的任何進(jìn)一步指令。如果 props 或狀態(tài)發(fā)生了更改泉沾,組件還將異步地重新運(yùn)行捞蚂。以下面的代碼為例,看看我們?nèi)绾问褂?setTimeout
設(shè)置一個人為的延遲狀態(tài):
import React, { useState } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const handleIncrement = () =>
setTimeout(
() => setCount(currentCount => currentCount + 1),
1000
);
const handleDecrement = () =>
setTimeout(
() => setCount(currentCount => currentCount - 1),
1000
);
return (
<div>
<h1>{count}</h1>
<Button handleClick={handleIncrement}>Increment</Button>
<Button handleClick={handleDecrement}>Decrement</Button>
</div>
);
};
const Button = ({ handleClick, children }) => (
<button type="button" onClick={handleClick}>
{children}
</button>
);
export default App;
Also note that we are using a callback function within the setCount
state function to access the current state. Since setter functions from useState
are executed asynchronously by nature, you want to make sure to perform your state change on the current state and not on any stale state.
還要注意跷究,我們在 setCount
狀態(tài)函數(shù)中使用了一個回調(diào)函數(shù)來訪問當(dāng)前狀態(tài)姓迅。由于 useState
中的 setter 函數(shù)本質(zhì)上是異步執(zhí)行的,因此你需要確保對當(dāng)前狀態(tài)執(zhí)行狀態(tài)更改,而不是對任何陳舊狀態(tài)執(zhí)行狀態(tài)更改丁存。
Experiment: If you wouldn't use the callback function within the State Hook, but rather act upon the count variable directly (e.g. setCount(count + 1)
), you wouldn't be able to increase the value from 0 to 2 with a quick double click, because both times the function would be executed on a count state of 0.
實(shí)驗(yàn):如果你不使用 State Hook 中的回調(diào)函數(shù)肩杈,而是直接作用于 count 變量(例如 setCount(count + 1)
),你無法通過快速雙擊將值從 0 增加到 2解寝,因?yàn)閮纱味紝⒃?count 狀態(tài)為 0 時執(zhí)行函數(shù)扩然。
Read more about how to fetch data with Function Components with React Hooks.
閱讀更多:如何使用 React 鉤子的函數(shù)組件獲取數(shù)據(jù)
React Function Component: Lifecycle(React 函數(shù)組件之生命周期)
If you have used React Class Components before, you may be used to lifecycle methods such as componentDidMount, componentWillUnmount and shouldComponentUpdate. You don't have these in Function Components, so let's see how you can implement them instead.
如果你以前使用過 React 類組件,那么你可能已經(jīng)熟悉了諸如 componentDidMount编丘、componentWillUnmount 和 shouldComponentUpdate 之類的生命周期方法与学。在函數(shù)組件中沒有這些,所以讓我們看看如何實(shí)現(xiàn)它們嘉抓。
First of all, you have no constructor in a Function Component. Usually the constructor would have been used in a React Class Component to allocate initial state. As you have seen, you don't need it in a Function Component, because you allocate initial state with the useState hook and set up functions within the Function Component for further business logic:
首先索守,函數(shù)組件中沒有構(gòu)造函數(shù)。通常在 React 類組件中使用構(gòu)造函數(shù)來分配初始狀態(tài)抑片。正如你所看到的卵佛,在函數(shù)組件中不需要它,是因?yàn)槭褂?useState 鉤子分配初始狀態(tài)敞斋,并在函數(shù)組件中為進(jìn)一步的業(yè)務(wù)邏輯設(shè)置函數(shù):
import React, { useState } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
return (
<div>
<h1>{count}</h1>
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
export default App;
React Functional Component: Mount(React 函數(shù)組件之掛載)
Second, there is the mounting lifecycle for React components when they are rendered for the first time. If you want to execute something when a React Function Component did mount, you can use the useEffect hook:
其次截汪,在首次渲染 React 組件時,有一個掛載生命周期植捎。如果你想在一個 React 函數(shù)組件 掛載 時做些事情衙解,你可以使用 useEffect 鉤子:
import React, { useState, useEffect } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
useEffect(() => setCount(currentCount => currentCount + 1), []);
return (
<div>
<h1>{count}</h1>
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
export default App;
If you try out this example, you will see the count 0 and 1 shortly displayed after each other. The first render of the component shows the count of 0 from the initial state -- whereas after the component did mount actually, the Effect Hook will run to set a new count state of 1.
如果你嘗試使用這個示例,你將看到 0 和 1 分別顯示在一起焰枢。組件的第一次渲染顯示了從初始狀態(tài)開始的 0 count(然而蚓峦,在組件實(shí)際掛載之后,Effect Hook 將運(yùn)行以設(shè)置新的 count 狀態(tài)為1)济锄。
It's important to note the empty array as second argument for the Effect Hook which makes sure to trigger the effect only on component load (mount) and component unload (unmount).
一定要注意暑椰,空數(shù)組是 Effect 鉤子的第二個參數(shù),它確保只在組件加載(mount)和組件卸載(unmount)時觸發(fā)效果荐绝。
Experiment: If you would leave the second argument of the Effect Hook empty, you would run into an infinite loop of increasing the count by 1, because the Effect Hook always runs after state has changed. Since the Effect Hook triggers another state change, it will run again and again to increase the count.
實(shí)驗(yàn):如果你讓 Effect 鉤子的第二個參數(shù)為空一汽,你會進(jìn)入一個無限循環(huán),計數(shù)增加 1低滩,因?yàn)?Effect 鉤子總是在狀態(tài)改變后運(yùn)行召夹。因?yàn)?Effect Hook 會觸發(fā)另一個狀態(tài)改變,所以它會一次又一次的運(yùn)行來增加計數(shù)恕沫。
React Functional Component: Update(React 函數(shù)組件之:更新)
Every time incoming props or state of the component change, the component triggers a rerender to display the latest status quo which is often derived from the props and state. A render executes everything within the Function Component's body.
每當(dāng)輸入的 props 或組件的狀態(tài)更改時戳鹅,組件將觸發(fā)一個重新運(yùn)行程序來顯示最新的狀態(tài),這些狀態(tài)通常來自 props 和狀態(tài)昏兆。渲染執(zhí)行函數(shù)組件主體內(nèi)的所有內(nèi)容。
Note: In case a Function Component is not updating properly in your application, it's always a good first debugging attempt to console log state and props of the component. If both don't change, there is no new render executed, and hence you don't see a console log of the output in the first place.
注意:如果在你的應(yīng)用程序中某個函數(shù)組件沒有正確地更新,那么首先嘗試調(diào)試以控制該組件的日志狀態(tài)和 props 總是好的爬虱。如果兩者都沒有改變隶债,就不會執(zhí)行新的渲染,因此你不會首先看到輸出的控制臺日志跑筝。
import React, { useState, useEffect } from 'react';
const App = () => {
console.log('Does it render?');
const [count, setCount] = useState(0);
console.log(`My count is ${count}!`);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
return (
<div>
<h1>{count}</h1>
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
export default App;
If you want to act upon a rerender, you can use the Effect Hook again to do something after the component did update:
如果你想在渲染時動作死讹,你可以使用 Effect 鉤子在組件更新后再次做一些事情:
import React, { useState, useEffect } from 'react';
const App = () => {
const initialCount = +localStorage.getItem('storageCount') || 0;
const [count, setCount] = useState(initialCount);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
useEffect(() => localStorage.setItem('storageCount', count));
return (
<div>
<h1>{count}</h1>
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
export default App;
Now every time the Function Component rerenders, the count is stored into the browser's local storage. Every time you fresh the browser page, the count from the browser's local storage, in case there is a count in the storage, is set as initial state.
現(xiàn)在,每次函數(shù)組件重新渲染時曲梗,count 都存儲在瀏覽器的本地存儲中赞警。每次刷新瀏覽器頁面時,來自瀏覽器本地存儲的 count(如果存儲中有)都被設(shè)置為初始狀態(tài)虏两。
You can also specify when the Effect Hook should run depending on the variables you pass into the array as second argument. Then every time one of the variables change, the Effect Hook runs. In this case it makes sense to store the count only if the count has changed:
還可以根據(jù)傳遞給數(shù)組的第二個參數(shù)變量來確定何時運(yùn)行 Effect Hook愧旦。然后,每當(dāng)變量發(fā)生變化時定罢,Effect Hook 就會運(yùn)行笤虫。在這種情況下,只有在 count 發(fā)生變化時才有必要存儲計數(shù):
import React, { useState, useEffect } from 'react';
const App = () => {
const initialCount = +localStorage.getItem('storageCount') || 0;
const [count, setCount] = useState(initialCount);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
useEffect(() => localStorage.setItem('storageCount', count), [
count,
]);
return (
<div>
<h1>{count}</h1>
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
export default App;
By using the second argument of the Effect Hook with care, you can decide whether it runs:
小心使用 Effect Hook 的第二個參數(shù)祖凫,你可以決定它是否運(yùn)行:
- every time (no argument)
每一次(無參數(shù))
- only on mount and unmount (
[]
argument)
只在掛載和非掛載時([]
參數(shù))
- only when a certain variable changes (e.g.
[count]
argument)
只有當(dāng)某個變量改變時(例如 [count]
)
Note: A React Function Component force update can be done by using this neat trick. However, you should be careful when applying this pattern, because maybe you can solve the problem a different way.
使用這個 精妙的技巧 可以完成一個 React 函數(shù)組件的強(qiáng)制更新琼蚯。但是,在應(yīng)用此模式時應(yīng)該小心惠况,畢竟還可以用其他途徑解決問題遭庶。
Pure React Function Component(純 React 函數(shù)組件)
React Class Components offered the possibility to decide whether a component has to rerender or not. It was achieved by using the PureComponent or shouldComponentUpdate to avoid performance bottlenecks in React by preventing rerenders. Let's take the following extended example:
React 類組件提供了一種可能性,可以決定組件是否必須重新渲染稠屠。它是通過使用 PureComponent 或 shouldComponentUpdate 來避免 React 中的性能瓶頸峦睡,從而防止渲染。讓我們舉一個擴(kuò)展的例子:
import React, { useState } from 'react';
const App = () => {
const [greeting, setGreeting] = useState('Hello React!');
const [count, setCount] = useState(0);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
const handleChange = event => setGreeting(event.target.value);
return (
<div>
<input type="text" onChange={handleChange} />
<Count count={count} />
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
const Count = ({ count }) => {
console.log('Does it (re)render?');
return <h1>{count}</h1>;
};
export default App;
In this case, every time you type something in the input field, the App component updates its state, rerenders, and rerenders the Count component as well. React memo -- which is one of React's top level APIs -- can be used for React Function Components to prevent a rerender when the incoming props of this component haven't changed:
在這種情況下完箩,每當(dāng)你在 input field 中鍵入一些內(nèi)容時赐俗,App 組件都會更新其狀態(tài)、重新渲染以及重新渲染 Count 組件弊知。React memo(React 的頂級 API 之一)可用于 React 函數(shù)組件阻逮,以防止在該組件的傳入 props 未更改時重新渲染:
import React, { useState, memo } from 'react';
const App = () => {
const [greeting, setGreeting] = useState('Hello React!');
const [count, setCount] = useState(0);
const handleIncrement = () =>
setCount(currentCount => currentCount + 1);
const handleDecrement = () =>
setCount(currentCount => currentCount - 1);
const handleChange = event => setGreeting(event.target.value);
return (
<div>
<input type="text" onChange={handleChange} />
<Count count={count} />
<button type="button" onClick={handleIncrement}>
Increment
</button>
<button type="button" onClick={handleDecrement}>
Decrement
</button>
</div>
);
};
const Count = memo(({ count }) => {
console.log('Does it (re)render?');
return <h1>{count}</h1>;
});
export default App;
Now, the Count component doesn't update anymore when the user types something into the input field. Only the App component rerenders. This performance optimization shouldn't be used as default though. I would recommend to check it out when you run into issues when the rerendering of components takes too long (e.g. rendering and updating a large list of items in a Table component).
現(xiàn)在,當(dāng)用戶在 input field 中輸入內(nèi)容時秩彤,Count 組件不再更新叔扼。只有 App 組件重新渲染。不過漫雷,這種性能優(yōu)化不應(yīng)該當(dāng)為默認(rèn)行為瓜富。我的建議是,在重新渲染組件的時間太長(例如降盹,在一個 Table 組件中渲染和更新一個很大的項(xiàng)目列表)而遇到問題時再進(jìn)行与柑。
React Function Component: Export and Import(React 函數(shù)組件之:Export 和 Import)
Eventually you will separate components into their own files. Since React Components are functions (or classes), you can use the standard import and export statements provided by JavaScript. For instance, you can define and export a component in one file:
最終你會將組件各自分離到獨(dú)立的文件中。因?yàn)?React 組件是函數(shù)(或類),所以可以使用 JavaScript 提供的標(biāo)準(zhǔn) import 和 export 語句价捧。例如丑念,你可以在一個文件中定義和導(dǎo)出一個組件:
// src/components/Headline.js
import React from 'react';
const Headline = (props) => {
return <h1>{props.value}</h1>;
};
export default Headline;
And import it in another file:
在另一個文件中將其導(dǎo)入:
// src/components/App.js
import React from 'react';
import Headline from './Headline.js';
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
};
export default App;
Note: If a Function Component is not defined, console log your exports and imports to get a better understanding of where you made a mistake. Maybe you used a named export and expected it to be a default export.
注意:如果沒有定義函數(shù)組件,控制臺將記錄你的導(dǎo)出和導(dǎo)入结蟋,以便更好地了解在哪里犯了錯誤脯倚。可能使用了一個具名導(dǎo)出嵌屎,并錯誤認(rèn)為它是一個默認(rèn)導(dǎo)出推正。
If you don't care about the component name by defining the variable, you can keep it as Anonymous Function Component when using a default export on the Function Component:
如果你不介意組件名稱由變量定義,你可以讓它作為匿名函數(shù)組件宝惰,此時使用默認(rèn)導(dǎo)出函數(shù)組件:
import React from 'react';
import Headline from './Headline.js';
export default () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
};
However, when doing it this way, React Dev Tools cannot identify the component because it has no display name. You may see an Unknown Component in your browser's developer tools.
但是植榕,當(dāng)這樣做時,React Dev 工具無法識別組件掌测,因?yàn)樗鼪]有顯示名稱内贮。可能會在瀏覽器的開發(fā)工具中看到一個未知的組件汞斧。
React Function Component: ref(React 函數(shù)組件之:ref)
A React Ref should only be used in rare cases such as accessing/manipulating the DOM manually (e.g. focus element), animations, and integrating third-party DOM libraries (e.g. D3). If you have to use a Ref in a Function Component, you can define it within the component. In the following case, the input field will get focused after the component did mount:
React Ref 應(yīng)該只在極少數(shù)情況下使用夜郁,比如手動訪問或操作 DOM(比如 focus 元素)、動畫以及集成第三方 DOM 庫(比如 D3)粘勒。如果必須在函數(shù)組件中使用 Ref竞端,則可以在組件中定義它。在以下情況下庙睡,組件掛載完成后事富,input field 將被聚焦:
import React, { useState, useEffect, useRef } from 'react';
const App = () => {
const [greeting, setGreeting] = useState('Hello React!');
const handleChange = event => setGreeting(event.target.value);
return (
<div>
<h1>{greeting}</h1>
<Input value={greeting} handleChange={handleChange} />
</div>
);
};
const Input = ({ value, handleChange }) => {
const ref = useRef();
useEffect(() => ref.current.focus(), []);
return (
<input
type="text"
value={value}
onChange={handleChange}
ref={ref}
/>
);
};
export default App;
However, React Function Components cannot be given refs! If you try the following, the ref will be assigned to the component instance but not to the actual DOM node.
但是,React 函數(shù)組件不能提供 ref乘陪!如果你嘗試以下操作统台,ref 被分配給組件實(shí)例,而不是實(shí)際的 DOM 節(jié)點(diǎn)啡邑。
// Doesn't work!
import React, { useState, useEffect, useRef } from 'react';
const App = () => {
const [greeting, setGreeting] = useState('Hello React!');
const handleChange = event => setGreeting(event.target.value);
const ref = useRef();
useEffect(() => ref.current.focus(), []);
return (
<div>
<h1>{greeting}</h1>
<Input value={greeting} handleChange={handleChange} ref={ref} />
</div>
);
};
const Input = ({ value, handleChange, ref }) => (
<input
type="text"
value={value}
onChange={handleChange}
ref={ref}
/>
);
export default App;
It's not recommended to pass a ref from a Parent Component to a Child Component and that's why the assumption has always been: React Function Components cannot have refs. However, if you need to pass a ref to a Function Component -- because you have to measure the size of a function component's DOM node, for example, or like in this case to focus an input field from the outside -- you can forward the ref:
不建議將 ref 從父組件傳遞給子組件贱勃,這就是為什么我們總是假設(shè):React 函數(shù)組件不能有 ref。但是谤逼,如果你需要將一個 ref 傳遞給一個函數(shù)組件(例如贵扰,因?yàn)槟惚仨殰y量函數(shù)組件的 DOM 節(jié)點(diǎn)的大小,或者像本例中那樣從外部聚焦一個 input field)流部,那么你可以 轉(zhuǎn)發(fā)這個 ref戚绕。
// Does work!
import React, {
useState,
useEffect,
useRef,
forwardRef,
} from 'react';
const App = () => {
const [greeting, setGreeting] = useState('Hello React!');
const handleChange = event => setGreeting(event.target.value);
const ref = useRef();
useEffect(() => ref.current.focus(), []);
return (
<div>
<h1>{greeting}</h1>
<Input value={greeting} handleChange={handleChange} ref={ref} />
</div>
);
};
const Input = forwardRef(({ value, handleChange }, ref) => (
<input
type="text"
value={value}
onChange={handleChange}
ref={ref}
/>
));
export default App;
There are a few other things you may want to know about React Refs, so check out this article: How to use Ref in React or the official React documentation.
關(guān)于 React Ref,你可能還想了解其他一些事情枝冀,所以請閱讀:如何在 React 中使用 Ref 或 官方 React 文檔舞丛。
React Function Component: PropTypes(React 函數(shù)組件之:PropTypes)
PropTypes can be used for React Class Components and Function Components the same way. Once you have defined your component, you can assign it PropTypes to validate the incoming props of a component:
PropTypes 可以以相同的方式用于 React 類組件和函數(shù)組件耘子。一旦你定義了你的組件,你可以分配它 PropTypes 來驗(yàn)證組件的輸入 props:
import React from 'react';
import PropTypes from 'prop-types';
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
};
const Headline = ({ value }) => {
return <h1>{value}</h1>;
};
Headline.propTypes = {
value: PropTypes.string.isRequired,
};
export default App;
Note that you have to install the standalone React prop-types, because it has been removed from the React core library a while ago. If you want to learn more about PropTypes in React, check out the official documentation.
請注意瓷马,你必須安裝獨(dú)立的 React prop-types拴还,因?yàn)樗呀?jīng)從 React 核心庫中刪除了一段時間了。如果你想了解更多關(guān)于 React 中 PropTypes 的信息欧聘,請查看 官方文檔。
In addition, previously you have seen the usage of default props for a Function Component. For the sake of completeness, this is another one:
此外端盆,在前面你已經(jīng)看到了函數(shù)組件默認(rèn) props 的使用怀骤。為了完整起見,這是另一個例子:
import React from 'react';
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline headline={greeting} />;
};
const Headline = ({ headline }) => {
return <h1>{headline}</h1>;
};
Headline.defaultProps = {
headline: 'Hello Component',
};
export default App;
Note that you can also use the default assignment when destructuring the value from the props in the function signature (e.g. const Headline = ({ headline = 'Hello Component' }) =>
) or the ||
operator within the Function Component's body (e.g. return <h1>{headline || 'Hello Component'}</h1>;
).
注意焕妙,你還可以在從函數(shù)簽名中的 props 中解構(gòu)值時使用默認(rèn)賦值(例如 const Headline = ({ headline = 'Hello Component' }) =>
)或者 ||
運(yùn)算符蒋伦,在函數(shù)組件主體中(例如 return <h1>{headline || 'Hello Component'}</h1>;
)。
However, if you really want to go all-in with strongly typed components in React, you have to check out TypeScript which is briefly shown in the next section.
React Function Component: TypeScript(React 函數(shù)組件之:TypeScript)
If you are looking for a type system for your React application, you should give TypeScript for React Components a chance. A strongly typed language like TypeScript comes with many benefits for your developer experience ranging from IDE support to a more robust code base. You may wonder: How much different would a React Function Component with TypeScript be? Check out the following typed component:
如果你正在為你的 React 應(yīng)用程序?qū)ふ翌愋拖到y(tǒng)焚鹊,你應(yīng)該給 React 組件的 TypeScript 一個機(jī)會痕届。像 TypeScript 這樣的強(qiáng)類型語言無論 IDE 支持還是更健壯的代碼庫,都會為你的開發(fā)體驗(yàn)帶來很多好處末患。你可能想知道:React 函數(shù)組件與 TypeScript 有多大的不同研叫?查看以下類型的組件:
import React, { useState } from 'react';
const App = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
const handleChange = event => setGreeting(event.target.value);
return (
<Headline headline={greeting} onChangeHeadline={handleChange} />
);
};
const Headline = ({
headline,
onChangeHeadline,
}: {
headline: string,
onChangeHeadline: Function,
}) => (
<div>
<h1>{headline}</h1>
<input type="text" value={headline} onChange={onChangeHeadline} />
</div>
);
export default App;
It only defines the incoming props as types. However, most of the time type inference just works out of the box. For instance, the use State Hook from the App component doesn't need to be typed, because from the initial value the types for greeting
and setGreeting
are inferred.
它只將傳入的 props 定義為類型。然而璧针,大多數(shù)時候類型推斷都是開箱即用的嚷炉。例如,不需要輸入來自 App 組件的 useState Hook探橱,因?yàn)閺某跏贾悼梢酝茢喑?greeting
和 setGreeting
的類型申屹。
If you want to know how to get started with TypeScript in React, check out this comprehensive cheatsheet ranging from TypeScript setup to TypeScript recipes. It's well maintained and my go-to resource to learn more about it.
如果你想知道如何在 React 中使用 TypeScript,可以查看 comprehensive cheatsheet ranging from TypeScript setup to TypeScript recipes隧膏。它得到了很好的維護(hù)哗讥,是我了解它的首選資源。
React Function Component vs Class Component(React 的函數(shù)組件和類組件)
This section will not present you any performance benchmark for Class Components vs Functional Components, but a few words from my side about where React may go in the future.
本節(jié)不會向你展示任何類組件與函數(shù)組件的性能基準(zhǔn)測試胞枕,但是我將簡要介紹未來 React 的發(fā)展方向杆煞。
Since React Hooks have been introduced in React, Function Components are not anymore behind Class Components feature-wise. You can have state, side-effects and lifecycle methods in React Function Components now. That's why I strongly believe React will move more towards Functional Components, because they are more lightweight than Class Components and offer a sophisticated API for reusable yet encapsulated logic with React Hooks.
自從在 React 中引入了 React 鉤子之后,函數(shù)組件的特性就不再落后于類組件了曲稼。你現(xiàn)在可以在 React 函數(shù)組件中使用狀態(tài)索绪、副作用和生命周期方法。這就是為什么我堅信 React 將更多地向函數(shù)組件發(fā)展贫悄,因?yàn)樗鼈儽阮惤M件更輕量株搔,并為使用 React 鉤子的可重用但封裝的邏輯提供了成熟的 API耗啦。
For the sake of comparison, check out the implementation of the following Class Component vs Functional Component:
為了比較,請查看以下類組件和函數(shù)組件的實(shí)現(xiàn):
// Class Component
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: localStorage.getItem('myValueInLocalStorage') || '',
};
}
componentDidUpdate() {
localStorage.setItem('myValueInLocalStorage', this.state.value);
}
onChange = event => {
this.setState({ value: event.target.value });
};
render() {
return (
<div>
<h1>Hello React ES6 Class Component!</h1>
<input
value={this.state.value}
type="text"
onChange={this.onChange}
/>
<p>{this.state.value}</p>
</div>
);
}
}
// Function Component
const App = () => {
const [value, setValue] = React.useState(
localStorage.getItem('myValueInLocalStorage') || '',
);
React.useEffect(() => {
localStorage.setItem('myValueInLocalStorage', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React Function Component!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
If you are interested in moving from Class Components to Function Components, check out this guide: A migration path from React Class Components to Function Components with React Hooks. However, there is no need to panic because you don't have to migrate all your React components now. Maybe it's a better idea to start implementing your future components as Function Components instead.
如果你對從類組件遷移到函數(shù)組件感興趣,請查看以下指南:使用 React 鉤子將 React 類組件遷移到函數(shù)組件的路徑。但是摹菠,沒有必要盲目,因?yàn)槟悻F(xiàn)在不必遷移所有的 React 組件。也許最好開始將未來的組件實(shí)現(xiàn)為函數(shù)組件肠缨。
The article has shown you almost everything you need to know to get started with React Function Components. If you want to dig deeper into testing React Components for instance, check out this in-depth guide: Testing React Components. Anyway, I hope there have been a couple of best practices for using Functional Components in React as well. Let me know if anything is missing!
本文向你展示了開始使用 React 函數(shù)組件所需的幾乎所有知識。例如盏阶,如果你想更深入地研究 testing React 組件晒奕,請查看以下深入指南:Testing React Components。無論如何名斟,我希望已經(jīng)有了一些在 React 中使用函數(shù)組件的最佳實(shí)踐脑慧。如果有什么遺漏,請告訴我砰盐!