我的筆記, 轉載請註明html
轉載自 szhshp的第三邊境研究所react
In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.git
通常狀況下想要刷新child elem必須經過新的prop刷新, 可是其實能夠有另外一個方法, 就是使用refgithub
There are a few good use cases for refs:express
Avoid using refs for anything that can be done declaratively.api
For example, instead of exposing open() and close()methods on a Dialog component, pass an isOpen prop to it.數組
使用ref以前切記要肯定一下對應的屬性是否是可使用prop代替, 開發時應該儘量聽從React推薦的信息流閉包
React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.app
關於ref有這些特色:less
例子:
class CustomTextInput extends React.Component { constructor(props) { super(props); this.focusTextInput = this.focusTextInput.bind(this); } focusTextInput() { // Explicitly focus the text input using the raw DOM API // 3. 所以這兒能夠經過this.textInput調用focus()方法 this.textInput.focus(); } render() { // Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput). // 1. Component載入的時候就會執行ref裏面的callback. // 2. 而後這個Elem會當作參數傳入, 所以就能夠經過this.textInput引用這個DOM elem return ( <div> <input type="text" ref={(input) => { this.textInput = input; }} /> <input type="button" value="Focus the text input" onClick={this.focusTextInput} /> </div> ); } }
相似ref在HTML DOM中的使用, 將ref賦值給自定義Component的時候, ref對應的callback就會接受自身這個instance做爲參數
注意: 必需要這個自定義Component是個完整的class, 不能夠是函數
When the ref attribute is used on a custom component declared as a class, the ref callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the CustomTextInput above to simulate it being clicked immediately after mounting:
class AutoFocusTextInput extends React.Component { componentDidMount() { // 2. 這兒就能夠對這個instance進行引用 this.textInput.focusTextInput(); } render() { return ( <CustomTextInput // 1. 對於自定義的Component, ref對應的callback會將自身這個instance當作參數傳進去 ref={(input) => { this.textInput = input; }} /> ); } }
通常數據流不該該在Parent Class裏面控制Child Class, 可是偶爾就有這樣傻逼的需求.
這時候用ref最適合了, 可是依然不推薦這麼使用.
更好的解決辦法是你和需求分析的人打一架而後讓他根據代碼改需求
固然上文提到了解決辦法是讓child class暴露一個prop, 可是這個辦法沒法對function Component使用.
另外下面這個辦法對function Component也有用:
function CustomTextInput(props) { // 2. 在child component裏面將這個callback賦值給ref // 2+. 固然這兒只能用ref這個attr // 3. 而後這個child component在mount/unmount的時候就會執行這個callback return ( <div> <input ref={props.inputRef} /> </div> ); } class Parent extends React.Component { render() { // `Parent` passes its ref callback as an `inputRef`prop to the `CustomTextInput` // 1. 這兒提供一個callback做爲props.inputReg return ( <CustomTextInput inputRef={el => this.inputElement = el} /> ); } }
最終在parent component中就能夠經過inputElement這個變量調用到對應輸入框元素.
並且這個能夠逐級傳遞, 好比下面這個隔代傳遞的例子:
function CustomTextInput(props) { return ( <div> <input ref={props.inputRef} /> </div> ); } function Parent(props) { return ( <div> My input: <CustomTextInput inputRef={props.inputRef} /> </div> ); } class Grandparent extends React.Component { render() { return ( <Parent inputRef={el => this.inputElement = el} /> ); } }
看起來暴露DOM有些彆扭, 可是不少時候需求就是比較特別. 所以上面是推薦用法.
舊版本React裏面曾經有過使用this.refs.textInput的用法, 其中ref會指向一段字符串, 新版本React不推薦如此使用
若是ref是個inline function, updates的時候會被調用兩次. 第一次是null而後第二次是DOM Elem.
這個是由於update的時候React須要清理舊的而且創建新的component
爲了防止這個問題, 能夠將ref callback和對應class進行綁定.
即便不綁定也不會引起太多問題
JSX將經過Babel進行編譯.
<MyButton color="blue" shadowSize={2}> Click Me </MyButton>
compiles into:
React.createElement( MyButton, {color: 'blue', shadowSize: 2}, 'Click Me' )
You can also use the self-closing form of the tag if there are no children. So:
<div className="sidebar" />
compiles into:
React.createElement( 'div', {className: 'sidebar'}, null )
通常Component使用大寫字母開頭, 若是在當前JSX裏面使用<XXX/>那麼XXX這個Component就必須出如今Scope以內.
另外可使用import語句將Component引用到Scope內
import React from 'react'; const MyComponents = { DatePicker: function DatePicker(props) { return <div>Imagine a {props.color} datepicker here.</div>; } } //下方使用圓點標識符調用了子屬性 function BlueDatePicker() { return <MyComponents.DatePicker color="blue" />; }
自定義Component(好比 <MyComponent/>)應該大寫字母開頭
系統自帶的Component(好比 <div/>)應該小寫字母開頭
不然系統會拋出警告
注意JSX Obj的tags必須是完整的單詞, 若是想要動態生成tag名稱能夠用賦值的辦法
錯誤的例子:
function Story(props) { // Wrong! JSX type can't be an expression. return <components[props.storyType] story={props.story} />; }
正確的作法:
function Story(props) { // Correct! JSX type can be a capitalized variable. const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />; }
關於使用JS表達式做爲prop:
<MyComponent foo={1 + 2 + 3 + 4} />
不可以直接使用, 可是能夠用這個替代方法:
function NumberDescriber(props) { let description; // check the condition if (props.number % 2 == 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>; }
另一個很實用的條件判斷的snippet
This can be useful to conditionally render React elements. This JSX only renders a <Header /> if showHeader is true:
<div>
{showHeader && <Header />}
<Content />
</div>
### String Literals When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:
<MyComponent message="<3" />
<MyComponent message={'<3'} />
### Props Default to 「True」 If you pass no value for a prop, it defaults to true. These two JSX expressions are equivalent:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
### Spread Attributes If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a 「spread」 operator to pass the whole props object. These two components are equivalent: >提供Props時, 如有一個Obj而且這個Obj裏面全部Attr和須要的Prop相匹配, 那麼可使用`spread` operator 進行賦值
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
另外對於`spread` operator也能夠給部分值賦值:
const Button = props => {
//將傳進函數裏面的props.kind 賦值給kind, 將其餘屬性賦值給...other
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
//而後將...other傳給button這個elem, 而沒有傳遞kind這個參數
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};
> # 關於解構運算符 > >MDN參考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator > 這玩意是ES6新引進的運算符, 經過三個點進行引用`...` > > ``` >function sum(x,y,z){ return x+y+z } > console.log(sum(...[1,2,3])) //6 console.log(sum(...[1,2,3,4,5])) //6 console.log(sum(...[1,,3,4,5])) //NaN > var doSomething = function(...args){ return sum(..args) } > console.log(doSomething(...[1,2,3])) //6 > //對Object是否有效呢? var obj = { a:"A", b:"B", c:"C", d:"D", e:"E" } var {a,b,...others} = obj //報錯var {a,b,...others} = obj //報錯
在老版本ES6中, 對Obj進行解構賦值會報錯, 可是JSX中容許這樣的使用.
子元素所有會經過props.children進行引用.
另外若是沒有子tag而只是放置了一段文本, 那麼props.children就會是tag之間的一段字符串
Hint: HTML is unescaped!
<MyComponent>Hello world!</MyComponent> <div>This is valid HTML & JSX at the same time.</div>
tags之間的空格和空行都會被忽略.
<div> Hello World </div>
另外也能夠將JS表達式用於child elem. 好比一個很典型的使用數組循環生成列表的例子:
return ( <ul> {todos.map((message) => <Item key={message} message={message} />)} </ul> );
反正只要最後返回的是一個完整的JSX Obj便可
// 2. 咱們在渲染parent elem function Repeat(props) { let items = []; for (let i = 0; i < props.numTimes; i++) { // 3. 經過調用child elem對應的函數生成jsx obj items.push(props.children(i)); } return <div>{items}</div>; } // 1. 返回的JSX obj的child elem是個函數 function ListOfTenThings() { return ( <Repeat numTimes={10}> {(index) => <div key={index}>This is item {index} in the list</div>} </Repeat> ); }
false, null, undefined, and true are valid children. They simply don’t render. These JSX expressions will all render to the same thing:
<div /> <div></div> <div>{false}</div> <div>{null}</div> <div>{undefined}</div> <div>{true}</div>
就是React項目流程的rethinking
[圖片上傳失敗...(image-af5c7e-1512723756201)]
以前提到過的三個原則進行判斷:
React從頭至尾就只有一條數據流有這些須要注意的:
就是數據的各類交互唄
一個重要的概念:
有些時候parent class可能會給child class提供一個eventHandler()
這玩意能夠當作一種callback, 賦值給child class的onchange, child class經過調用這個onChange使得parent class的state變化.
若是隻有一個值的狀況下甚至能夠不用給child class設置任何的state# React: 關於setState()
這個八成是由於在setState的同一個方法裏面調用了this.state
這時候獲取到的state都是前一個state
下方是參考文獻:
原文: https://medium.com/@mweststra...
做者: Michel Weststrate
這篇文章原標題是3 Reasons why I stopped using React.setState,可是我對原文做者提出的論點不是很感冒,可是做者提出的三點對React新手來講是很容易忽略的地方,因此我在這裏只提出部份內容,並且把標題改成使用React.setState須要注意的三點。
對React新手來講,使用setState是一件很複雜的事情。即便是熟練的React開發,也頗有可能由於React的一些機制而產生一些bug,好比下面這個例子:
文檔中也說明了當使用setState的時候,須要注意什麼問題:
注意:
絕對不要 直接改變this.state,由於以後調用setState()可能會替換掉你作的改變。把this.state當作是不可變的。setState()不會馬上改變this.state,而是建立一個即將處理的state轉變。在調用該方法以後訪問this.state可能會返回現有的值。
對setState的調用沒有任何同步性的保證,而且調用可能會爲了性能收益批量執行。
setState()將老是觸發一次重繪,除非在shouldComponentUpdate()中實現了條件渲染邏輯。若是可變對象被使用了,但又不能在shouldComponentUpdate()中實現這種邏輯,僅在新state和以前的state存在差別的時候調用setState()能夠避免沒必要要的從新渲染。
總結出來,當使用setState的時候,有三個問題須要注意:
不少開發剛開始沒有注意到setState是異步的。若是你修改一些state,而後直接查看它,你會看到以前的state。這是setState中最容易出錯的地方。 setState這個詞看起來並不像是異步的,因此若是你不假思索的用它,可能會形成bugs。下面這個例子很好的展現了這個問題:
class Select extends React.Component { constructor(props, context) { super(props, context) this.state = { selection: props.values[0] }; } render() { return ( <ul onKeyDown={this.onKeyDown} tabIndex={0}> {this.props.values.map(value => <li className={value === this.state.selection ? 'selected' : ''} key={value} onClick={() => this.onSelect(value)} > {value} </li> )} </ul> ) } onSelect(value) { this.setState({ selection: value }) this.fireOnSelect() } onKeyDown = (e) => { const {values} = this.props const idx = values.indexOf(this.state.selection) if (e.keyCode === 38 && idx > 0) { /* up */ this.setState({ selection: values[idx - 1] }) } else if (e.keyCode === 40 && idx < values.length -1) { /* down */ this.setState({ selection: values[idx + 1] }) } this.fireOnSelect() } fireOnSelect() { if (typeof this.props.onSelect === "function") this.props.onSelect(this.state.selection) /* not what you expected..*/ } } ReactDOM.render( <Select values={["State.", "Should.", "Be.", "Synchronous."]} onSelect={value => console.log(value)} />, document.getElementById("app") )
第一眼看上去,這個代碼彷佛沒有什麼問題。兩個事件處理中調用onSelect方法。可是,這個Select組件中有一個bug很好的展示了以前的GIF圖。onSelect方法永遠傳遞的是以前的state.selection值,由於當fireOnSelect調用的時候,setState尚未完成它的工做。我認爲React至少要把setState更名爲scheduleState或者把回掉函數設爲必須參數。
這個bug很容易修改,最難的地方在於你要知道有這個問題。
setState形成的第二個問題是:每次調用都會形成從新渲染。不少時候,這些從新渲染是沒必要要的。你能夠用React performance tools中的printWasted來查看何時會發生沒必要要渲染。可是,大概的說,沒必要要的渲染有如下幾個緣由:
新的state其實和以前的是同樣的。這個問題一般能夠經過shouldComponentUpdate來解決。也能夠用pure render或者其餘的庫來解決這個問題。
一般發生改變的state是和渲染有關的,可是也有例外。好比,有些數據是根據某些狀態來顯示的。
第三,有些state和渲染一點關係都沒有。有一些state多是和事件、timer ID有關的。
基於上面的最後一條,並非全部的組件狀態都應該用setState來進行保存和更新的。複雜的組件可能會有各類各樣的狀態須要管理。用setState來管理這些狀態不但會形成不少不須要的從新渲染,也會形成相關的生命週期鉤子一直被調用,從而形成不少奇怪的問題。
在原文中做者推薦了一個叫作MobX的庫來管理部分狀態,我不是很感冒,因此我就不介紹。若是感興趣的,能夠經過最上面的連接看看原文中的介紹。
基於上面提出的三點,我認爲新手應該注意的地方是:
setState是不保證同步的,是不保證同步的,是不保證同步的。重要的事情說三遍。之因此不說它是異步的,是由於setState在某些狀況下也是同步更新的。能夠參考這篇文章
若是須要在setState後直接獲取修改後的值,那麼有幾個方案:
針對於以前的例子,徹底能夠在調用fireOnSelect的時候,傳入須要的值。而不是在方法中在經過this.state來獲取
setState方法接收一個function做爲回調函數。這個回掉函數會在setState完成之後直接調用,這樣就能夠獲取最新的state。對於以前的例子,就能夠這樣:
this.setState({ selection: value }, this.fireOnSelect)
在setState使用setTimeout來讓setState先完成之後再執行裏面內容。這樣子:
this.setState({ selection: value }); setTimeout(this.fireOnSelect, 0);
直接輸出,回調函數,setTimeout對比
componentDidMount(){ this.setState({val: this.state.val + 1}, ()=>{ console.log("In callback " + this.state.val); }); console.log("Direct call " + this.state.val); setTimeout(()=>{ console.log("begin of setTimeout" + this.state.val); this.setState({val: this.state.val + 1}, ()=>{ console.log("setTimeout setState callback " + this.state.val); }); setTimeout(()=>{ console.log("setTimeout of settimeout " + this.state.val); }, 0); console.log("end of setTimeout " + this.state.val); }, 0); }
若是val默認爲0, 輸入的結果是:
> Direct call 0 > In callback 1 > begin of setTimeout 1 > setTimeout setState callback 2 > end of setTimeout 2 > setTimeout of settimeout 2
一般state中只來管理和渲染有關的狀態,從而保證setState改變的狀態都是和渲染有關的狀態。這樣子就能夠避免沒必要要的重複渲染。其餘和渲染無關的狀態,能夠直接以屬性的形式保存在組件中,在須要的時候調用和改變,不會形成渲染。或者參考原文中的MobX。
避免沒必要要的修改,當state的值沒有發生改變的時候,儘可能不要使用setState。雖然shouldComponentUpdate和PureComponent能夠避免沒必要要的重複渲染,可是仍是增長了一層shallowEqual的調用,形成多餘的浪費。
以上
handleStockedChange(e){ var value = e.target.type === 'checkbox' ? e.target.checked : e.target.value; }
八成就是return後面換行了, JS會自動加分號因此返回了undefined
這個八成就是寫了兩個elem或者某個elem沒有閉合
不推薦使用繼承
我也不推薦
Anything inside the <FancyBorder> JSX tag gets passed into the FancyBorder component as a children prop.
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
通常h5的input本身會管理本身的輸入
<span style="color: red;"> 實際上就是兩點:</span>
React也能夠在渲染的時候綁定事件, 事件裏面就能夠進行各類操做, 好比轉換全部文本爲uppercase之類的。另外修改了文本以後也能夠馬上反應/渲染到元素之上。
相似於將JS端的onChange放到了Server
handleChange(event) { //經過變量event.target.value獲取輸入的值而且設置state this.setState({value: event.target.value}); } handleSubmit(event) { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> //綁定onSubmit <label> Name: <input type="text" value={this.state.value} onChange={this.handleChange} /> //綁定onChange </label> <input type="submit" value="Submit" /> </form> ); }
有一點和H5不一樣的地方, React端的value的設置能夠經過一個attr:
H5:
<textarea> Hello there, this is some text in a text area </textarea>
React:
<textarea value={this.state.value} onChange={this.handleChange} />
設置selected的option的時候也略有不一樣, 一樣能夠經過value這個attr設置
H5:
<select> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option selected value="coconut">Coconut</option> <option value="mango">Mango</option> </select>
React:
<select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut">Coconut</option> <option value="mango">Mango</option> </select>
能夠看到, 將input的value設置爲this.state.value就是爲了阻止用戶自由輸入, 可是有些時候要將controlled Input的權限放開, 所以咱們能夠將value設置爲null或者undefined來開啓用戶自由輸入.
ReactDOM.render(<input value="hi" />, mountNode); // allow user input after 1sec setTimeout(function() { ReactDOM.render(<input value={null} />, mountNode); }, 1000);
縮寫成CC/UC
CC寫起來其實挺麻煩, 由於每一個elem都要寫個onChange.
其實也可使用UC
使用UC的例子:
handleSubmit(event) { alert('A name was submitted: ' + this.input.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={(input) => this.input = input} /> </label> <input type="submit" value="Submit" /> </form> ); }
通常將key放置到列表class裏面進行賦值, 而不是放到item裏面進行賦值
最好放在ul循環生成li的時候給li添加key
function ListItem(props) { const value = props.value; return ( // Wrong! There is no need to specify the key here // 固然在這兒也得到不到key值 <li key={value.toString()}> {value} </li> ); } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // Wrong! The key should have been specified here: <ListItem value={number} /> ); return ( <ul> {listItems} </ul> ); }
正確用法:
function ListItem(props) { // Correct! There is no need to specify the key here: return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // Correct! Key should be specified inside the array. <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); }
不要return一個JSX Obj, return null 便可
return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && //注意這裏, 前面實際上是一個條件 <h2> You have {unreadMessages.length} unread messages. </h2> } </div> );
return ( <div> The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div> );
return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> );
幾個要點:
For example, the HTML:
<button onclick="activateLasers()"> Activate Lasers </button>
is slightly different in React:
<button onClick={activateLasers}> Activate Lasers </button>
Another difference is that you cannot return false to prevent default behavior in React. You must call preventDefault explicitly.
防止默認事件的代碼須要一些修正
<a href="#" onclick="console.log('The link was clicked.'); return false"> Click me </a>
In React, this could instead be:
function ActionLink() { function handleClick(e) { e.preventDefault(); // must be called implicitly console.log('The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a> ); }
When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created.
Instead, just provide a listener when the element is initially rendered.
初始化的時候給事件管理器,DOM初始化以後就別去添加其餘監聽器了。
JQuery: ...
class Welcome extends React.Component{ constructor(props) { super(props); this.state = {isToggleOn: true}; this.handleClick = this.handleClick.bind(this); //綁定一下事件到this } handleClick() { console.log(123) this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render(){ return ( <div onClick={this.handleClick}> //這裏記得要寫一個attr,而且要注意大小寫 {(this.state.isToggleOn)?'A':'B'}, {this.props.name} </div> ); } }
下方的ID表明對應數據編號, 既可使用外部的循環Index.
這兒有點像是閉包
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
兩種模式相似, 重點在於必定要將React event傳進去
來源: https://reactjs.org/docs/handling-events.html
class component看起來不能經過函數的方式進行調用
那麼就改爲tag模式調用就行:
render(){ return ( <div> <WelcomeLList nameList={nameList}/> // {WelcomeList(this.props.nameList)} // ↑↑ dont use this way if you created class component </div> ); }
其實和Java的class同樣,render裏面能夠直接調用prop參數了
class Root extends React.Component{ constructor(props) { super(props); } render(){ return ( <div> {WelcomeList(this.props.nameList)} //這裏能夠直接使用this.prop </div> ); } }
簡單易懂,直接賦值一個數組便可,不用加雙引號,否則會被當作長字符串
var nameList = ["Mike","Jack","Dick"]; ReactDOM.render( <Root nameList={nameList}/>, // <Root nameList="{nameList}"/>, // This is wrong document.getElementById('root') );
相似於Android的生命週期調節參數,此外state必須在定義它的那個class裏面使用。
另外能夠將state傳到子元素,不過不能傳給其餘同級元素或者父元素
所以只可能出現Down Flow不可能向上傳遞。
另外stateful的Component和stateless的Component徹底能夠隨意交叉使用,反正數據均可以相互傳遞
<h2>It is {this.state.date.toLocaleTimeString()}.</h2> <FormattedDate date={this.state.date} />
對於一個Component:
而後能夠在這兩個事件進行監聽
所以對於一個定時器來講,應該在componentDidMount()事件裏面註冊Timer而且在componentWillUnmount()事件裏面關閉Timer
而後在Timer裏面必須更新state數據,由於咱們會將state數據輸出出來,更新state須要執行setState(),將參數傳進去就行
簡單易懂
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
幾個關於setState()的要點:
// Wrong this.state.comment = 'Hello';
// Correct this.setState({comment: 'Hello'});
The only place where you can assign this.state is the constructor.
所以不能直接使用state來overwite state
React may batch multiple setState() calls into a single update for performance.
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
寫一個閉包能夠解決問題
// Correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
When you call setState(), React merges the object you provide into the current state.
使用 setState()的時候,只要沒有提供value的state都不會改變
For example, your state may contain several independent variables:
constructor(props) { super(props); this.state = { posts: [], comments: [] }; }
Then you can update them independently with separate setState()calls:
componentDidMount() { fetchPosts().then(response => { this.setState({ posts: response.posts }); }); fetchComments().then(response => { this.setState({ comments: response.comments }); }); }
The merging is shallow, so this.setState({comments}) leaves this.state.posts intact, but completely replaces this.state.comments.
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
We will move the date from props to state in three steps:
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
class Clock extends React.Component { constructor(props) { //!!!!!!!!!!!!!! super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
Note how we pass props to the base constructor:
constructor(props) { super(props); this.state = {date: new Date()}; }
Class components should always call the base constructor with props.
ReactDOM.render( <Clock />, document.getElementById('root') );
We will later add the timer code back to the component itself.
The result looks like this:
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
來源: https://reactjs.org/docs/state-and-lifecycle.html
用這個方法能夠循環生成多個子元素
function Welcome(props) { props.name = 'test'; return <h1>Hello, {props.name}</h1>; } function WelcomeList(nameList) { var nameDOM = []; for (var i = 0; i < nameList.length; i++) { nameDOM.push(Welcome({name: nameList[i]})) } return nameDOM; } function Root() { var nameList = ["Mike","Jack","Dick"]; return ( <div> {WelcomeList(nameList)} </div> ); } ReactDOM.render( <Root />, document.getElementById('root') );