这是react官方文档推荐的方法(源代码不多)
通常的state,例如层级比较浅的,能够直接用Object.assign
或者...
(扩展语法来解构),可是在层级比较深,或者操做数组的状况下reducer写起来就要麻烦些,这时候就能够用immutability helper的update
方法了javascript
//更新数组中的某一条数据 updatePurchaseDetail(state, { index, payload }) { return update(state, { purchaseDetails: { [index]: { $merge: payload } } }) },
//向数组中添加一条数据 遵循不可变数据结构 咱们不能直接用Push addPurchaseLine(state, { item }) { return update(state, { purchaseDetails: { $push: [item] } }) },
const collection = [1, 2, {a: [12, 17, 15]}]; const newCollection = update(collection, { 2: { a: { $splice: [[1, 1, 13, 14]] // [1,1,13,14]对应于数组的splice函数的参数 } } } ); // => [1, 2, {a: [12, 13, 14, 15]}] // 在collection数组索引2的对象的a属性的数组的索引1的位置插入13,14
react官方文档中这样介绍setState的html
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
setState
不会当即修改this.state
,也就是说咱们在调用setState
的后,当即访问this.state是不能取得最新的this.state的值的。这样在一些特殊需求的时候可能会出现问题。可是咱们能够经过使用setState回调函数的形式来使下面的代码拿到最新的this.state的值。java
updateState({target}) { this.setState(prevState => { const updatedUser = {...prevState.user, [target.name]: target.value}; // 使用先前的state来构建新的state的值 doSomething(updatedUser); return { user: updatedUser }; }); }
你们都知道使用好shouldComponentUpdate
能够优化性能,对props 和 state 的全部属性进行比较来决定组件是否须要更新, 这个函数默认都是返回true,也就是说须要更新。当咱们严格遵照不可变数据结构的时候,就能够继承React.PureComponent
来对props和state进行浅比较来决定组件是否应该更新,方便的优化咱们组件的性能。PureComponent
代替咱们作了下面例子中shouldComponentUpdate
函数作的事情.相关连接react
class CounterButton extends React.Component { constructor(props) { super(props); this.state = {count: 1}; } shouldComponentUpdate(nextProps, nextState) { if (this.props.color !== nextProps.color) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } }
在react中使用内联函数(在render方法里面定义的函数,并经过props传递到子组件)是很方便的,可是这样用也会影响应用的性能。
影响性能的缘由主要有两个
1.会常常触发垃圾回收机制
2.一个内联函数每次都是一个新的引用,也就是说每次都会触发子组件的render函数(这个时候使用PureComponent就无效了)webpack
class MyComponent extends React.Component { render() { const msg = "Hello " + this.props.user.name.first; return <PureChild onClick={() => this.props.onAlert(msg)} />; //另外一种形式 this.props.onAlert.bind(this, msg) } }
如何避免使用inline function
1.能够把数据绑定在元素上git
... //同一个函数须要处理多种状况的时候 handleClick = (ev) => { const { action } = ev.target.dataSet this.props.dispatch({ type: 'handleBpm', action }) } ... <Button data-action="Approve" onClick={this.handleClick}>approve</Button> <Button data-action="Reject" onClick={this.handleClick}>reject</Button>
2.把事件处理函数移到子组件github
// 父组件 ... render () { const msg = "Hello " + this.props.user.name.first; return ( <PureChild onAlert={this.props.onAlert} msg={msg} /> ) } // 子组件 PureChild handleClick = () => { //do something const { onAlert, msg } = this.props; onAlert(msg) } ... render () { return ( ... <div onClick={this.handleClick}></div> ) }
第二种方法须要咱们在能够编码子组件的状况下才能够作到
还有一种经过babel插件reflective-bind的方式能够参考
不仅是内联函数,咱们在render函数里面应该尽量少的声明实例,尽可能不把在render里生成的实例当作Props传递下去。web
Container与Component的主要区别在于:数组
1.Container是跟全局状态有关联的,一般被用来管理数据并经过connect函数链接到全局state,几乎不写样式 2.Component与样式联系紧密,可是不参与管理任何数据,只经过接收到的props响应数据更改
在dva中routes下面的文件目录至关于containers,也就是说咱们须要使用connect的组件就应该规划在这里面。
component文件目录就应该放置与全局state无关,能够复用的通用组件。babel
另外每个文件夹的入口文件能够用index.js命名,这样有两个明显的好处。第一点是可让阅读代码的人,一眼就知道在当前目录下,哪一个文件是入口文件。第二点是在其余文件Import目标文件的时候,只须要写到folderName的位置就能够了。webpack会自动读取当前文件目录下的index文件。
例如import Home from routes/home
而不用写成import Home from routes/home/index
关于react规范结构的问题 能够参考
how to scale react applications
react-boilerplate
Airbnb React 编码规范