我的笔记, 转载请注明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') );