翻譯自react的大部分文檔,方便本身查閱。javascript
僅僅關於客戶端的Reacthtml
不能直接設置state
, 這不會再次渲染一個component(this will not re-render a component), 只有一個地方能夠直接設置state。java
// wrong, this this.state = { comments: 'Hello world'};
應該使用setState()
方法。react
// true this.setState({ comments: 'Hello world', });
React能夠將多個setState()
調用分批到單個更新中以實現性能。git
由於this.props
與this.state
均可能是異步更新,所以不能夠依靠它們的值來計算下一次的state。舉例來講,下面就是錯的:es6
// wrong this.setState({ counter: this.state.counter + this.props.increment, });
爲了解決這個問題,使用setState()
的第二種形式,它接受一個函數,函數的第一個參數是以前的state, 第二個參數是props。github
// correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment, }));
當你調用setState()
的時候,React合併你提供的對象到當前的state當中。(When you call setState(), React merges the object you provide into the current state.)segmentfault
function MailBox(props) { return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); }
可是這種方法,值得注意的是,return後面跟的最外層必須是html元素。而不能是下面這樣:數組
function MailBox(props) { return ( {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } ); }
render() { const isLoggedIn = this.state.isLoggedIn; return( <div> The user is <b>{isLogginIn ? 'currently' : 'not'}</b> logged in. </div> ); }
還能夠用於更大的表達式。瀏覽器
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); }
極少的狀況下,要讓組件隱藏起來,那麼能夠經過return null
來實現。
在react中使用list,必需要爲每一個list的元素指定key(每一個item的key是惟一的)。
keys幫助React肯定哪些item已經改變了,被添加了或者被移除了。
不推薦設置key的值是索引,若是這個數組要被排序的話(We don't recommand using indexes for keys if the items can reorder, as that would be slow.)。由於這將會被慢。
key只在周圍數組的上下文中有意義。
在react中,HTML表單元素與其餘DOM元素有所不同。由於表單元素天然保持着一些內部狀態。舉例來講,這個HTML格式的表單接受一個單個的name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
這個表單擁有HTML表單的默認行爲,當提交表單的時候,瀏覽器會打開一個新的頁面。若是你在react中這麼使用的話,它依然起做用。可是在大多數狀況下,擁有一個能夠處理表單並可訪問用戶輸入表單的數據的JavaScript函數是很方便的。實現這一點的標準方法是使用一種叫做'受控組件'的技術。
在HTML中,相似於input textarea select
這樣的表單元素一般維持着它們本身的狀態,而且基於用戶的輸入更新。在React中,可變狀態一般保存在組件的state
屬性中,而且只能經過setState()
來更新。
咱們能夠經過使react成爲'真正的惟一來源', 將二者結合起來。而後,呈現表單的React組件也控制後續用戶輸入時該表單中發生的狀況。 一個輸入表單元素的值被React控制,被稱爲受控組件。
一個簡單的受控組件以下:
class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: '',}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ value: e.target.value, }); } handleSubmit(e) { console.log(this.state.value); e.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> name: <input type="text" value={this.state.value} onChange={this.handleChange} /> </labeL> <input type="submit" value="Submit" /> </form> ); } }
使用受控組件,每一個狀態的突變都具備相關聯的處理函數。這使得修改或驗證用戶的輸入很直接。舉例來講,若是咱們想要用戶強制性這些名稱用所有大寫字母寫,咱們能夠把handleChange寫爲:
handleChange(e) { this.setState({ value: e.target.value.toUpperCase(), }); }
在HTML中,一個textarea
元素定義它的文本經過children來定義。
而在React中,一個textarea
元素是使用value屬性來定義的。其使用方法和input
差很少的。
在HTML中,select建立一個下拉列表,好比像下面這樣的:
<select> <option value="baoma">baoma</option> <option selected value="benchi">benchi</option> <option value="aodi">aodi</option> </select>
而在React中,是在根select組件裏使用value屬性來選中的。在受控組件中,這更加方便,由於你只須要在一個地方更新它,好比下面這樣:
class FormItem extends React.Component { constructor(props) { super(props); this.state = {value: 'benchi'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ value: e.target.value, }); } handleSubmit(e) { console.log(e.state.value); e.preventDefault(); } render( return ( <form onSubmit={this.handleSubmit} <label> Pick your favorite car: <select value={this.state.value} onChange={this.handleChange}> <option value="baoma">baoma</option> <option value="benchi">benchi</option> <option value="aodi">aodi</option> </select> </label> <input type="submit" value="Submit" /> /> ); ); } <input type="text" /> <textarea> <select>它們都工做的差很少,它們都接受一個屬性,這個屬性能夠用來實現一個受控組件。value
當你須要處理多個受控組件input
元素的時候,你能夠給每一個元素添加name
屬性,而且讓處理函數根據該值(event.target.name)選擇要進行的操做。
舉個例子:
class Reservation extends React.Component { constructor(props) { super(props); this.setState = { isGoing: true, numberOfGuests: 2, }; this.handleChange = this.handleChange.bind(this); } handleChange(e) { const target = e.target; const value = target.type === 'checkbox' ? target.checked : target.value; const name = target.name; // es6 computed property name this.setState({ [name]: value, }); } render() { return ( <form> <label> Is going: <Input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleChange} /> </label> </br> <label> Number of guests: <input name="numberOfGuests" type="number" value=={this.state.numberOfGuests} onChange={this.handleChange} /> </label> </form> ); } }
可能你以爲太麻煩,你須要非受控組件
在react中,共享state是經過將它移動到須要它的組件的最接近的共同祖先來實現的。這被稱爲提高狀態。若是祖先擁有了共享狀態,那麼就有了source of true
。
官方文檔給的那個例子,簡單來講,兩個組件的值相互依賴的時候,就將state提高到它們最近的共同祖先,經過在父組件裏進行相應的值轉換,而後經過props將值傳遞給子組件。而後兩個子組件的值改變時,調用的函數是父組件傳遞下來的。
所以, 能夠經過子組件調父組件傳遞過來的函數,將子組件的值傳遞給父組件, 來改變父組件的state, 而後父組件計算值後,經過props將計算後的值分發到各個子組件,這樣就保證了惟一的來源,而子組件的值也是相互依賴(有關聯)的。 以下:
// 子組件 handleChange(e) { this.props.onTemperatureChange(e.target.value); } <input onChange={this.handleChange} type="text" /> // 父組件 handleChange(value) { this.setState({ temperature: value, }); } <TemperatureInput onTemperatureChage={this.handleChange} />
在React中,咱們推薦使用組合來複用代碼而不是繼承。
一些容器不能提早知道它們的children是誰。在Sidebar
和Dialog
裏尤爲的正常。
咱們推薦這類的組件使用特殊的children
prop來將children直接傳遞到它們的輸出中:
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {this.props.children} </div> ); }
而後讓其餘組件經過嵌入JSX傳遞任意個child給FancyBorder
:
function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
<FancyBorder>
JSX標籤中的任何內容都會做爲子菜單傳入FancyBorder組件。因爲FancyBorder
將{props.children}
呈如今
this.props.children
是誰。好比下面這樣:
// News.js render() { return ( <div className={style.container}> {this.props.children} </div> ); } // routers.js export function createRoutes() { return { path: '/', component: App, indexRoute: { component: Main }, childRoutes: [ { path: ':channel', component: NewsList, } ], }; }
這裏News組件的子組件就是NewsList。
雖然不常見,可是有時候你可能在組件裏須要多個'hole', 在這種狀況下,你可能想出本身的習慣,而不是使用children
:
function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); }
有時咱們將組件視爲其餘組件的"特殊狀況"。舉例來講,咱們能夠說WelcomeDialog
是Dialog
的一種特殊狀況。
在React中,這一般由組合來實現,其中一個更"特定"的組件呈現出更"通用的組件", 而且使用props
來配置它。
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-title"> {props.message} </p> </FancyBorder> ); } function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }
組合對於定義爲類的組件一樣適用。
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.messgae} </p> {props.children} </FancyBorder> ); } class SignUpDialog extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.handleSignUp = this.handleSignUp.bind(this); this.state = {login: ''}; } handleChange(e) { this.setState({ login: e.target.value, }); } handleSignUp() { alert(`Welcome aboard, ${this.state.login}!`); } render() { return ( <Dialog title="Mars Exploration Program" message="How should we refer to you?"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog> ); } }
在Facebook, 咱們在數千計的組件中,尚未發現任何一種狀況值得咱們推薦使用繼承。使用Props和composition就已經很完美了。
使用單一任務原則,也就是說,一個組件理想上只作一件事情。
使用mock數據構架一個沒有交互的靜態版本。由於構建一個靜態的版本,須要大量的typing
和不須要思考太多,而構建一個交互性的版本須要大量的思考,而不須要大量的typing
。
若是你很熟悉state
的概念,那麼就不要使用state
來構建靜態的版本, state
只是爲了交互而保留的。
你既能夠自下向上進行構建,也能夠自上向下構建。在簡單的例子中,一般更容易自上而下;而在較大的例子中,自下而上一般更容易一些,而且也更容易寫測試。
要使你的應用能夠交互,你須要可以觸發底層數據模型的更改, State
讓這一切變得很容易。
爲了正確的構建你的app,首先你須要思考你的app須要的最小的可變的state集。這裏很關鍵的是DRY: Don't repeat yourself。找出你的app須要的state集的最小表示,並計算出你所須要的其餘需求。舉例來講,若是你要構建一個Todo List
, 只須要維持一個todo items
的數組,不須要爲數量單獨保持一個state的變量。當你想要渲染todo的數量時,只須要取todos數組的長度就能夠了。
如何區分是數據是state仍是props,只須要問下面這三個問題:
當咱們肯定app的最小的state集後。下一步,咱們須要肯定是哪個組件擁有state。
記住: React是單向數據流,可能不能當即清楚哪一個組件擁有哪一個state。這對於新手來講也是最大的挑戰,所以根據下面這些步驟來解決這個問題:
對於你的應用中的每一個state:
find a common owner component
(單個組件,它是全部須要那個state的組件的父級組件)。子組件經過props調用父級組件 傳遞過來的方法(回調)來改變父級的state。