反应,将反应状态视为不可变是绝对必要的吗?

时间:2017-02-25 05:10:36

标签: reactjs immutability

我正在做这样的事情并想知道是否应该完全避免或接受。

因为将状态视为不可变状态会很复杂。

第一个版本是我通常做的

render() {
  var { blogs } = this.state
  var blogNodes = blogs.map((blog, i) => {
    return (
      <div>
        {blog.name}
        <Checkbox
          checked={blog.checked}
          onChange={
            (e, {name, value, checked}) => {
              blog.checked = checked
              this.setState({blogs})
            }
          }
          />
      </div>
    )
    })                                                                                                                                                                                   
} ,  

第二个版本似乎是更正确的版本

render() {
  var { blogs } = this.state                                                                                                                                                       
  var blogNodes = blogs.map((blog, i) => {                                                                                                                                          

  return (                                                                                                                                                                          
     <div>
        {blog.name}
        <Checkbox
          checked={blog.checked}
          onChange={
            (e, {name, value, checked}) => {
              blog.checked = checked
              var newState = update(this.state, {
                blogs: {
                  i: {
                    $set: {
                      checked: checked
                    }
                  }
                }
              })
              this.setState(newState)
            }
          }
          />
      </div>
    )
  })
}

将反应状态视为不可变状态还是仅仅出于性能原因,是否绝对必要?

如果我必须将它视为不可变的,那么上面的第二个版本是否有更简单的方法? 当我们手头有索引(i)时,会更烦人。

2 个答案:

答案 0 :(得分:1)

是否绝对必须保持组件状态不变?不,但重要的是要了解你为什么要这样做,特别是如果你在你的州树中嵌套(就像你的例子),这就是原因

当所述组件的状态(或道具)更新时,React更新组件,并且有关react的最佳部分是,您可以使用shouldComponentUpdate()生命周期事件对此更新进行TOTAL控制,所以..如果你正在改变你的状态对象,然后你将不得不做一些被称为深度资产检查的东西,以确定状态何时更新,当状态对象内部有更多嵌套时,这会变得更糟,

现在想象一下将状态保持为不可变对象,并最终得到这个明确且易于预测的漂亮状态对象,并且可以相应地优化组件以获得更好的性能......

其次,默认情况下做出反应,不要进行深度资产检查以查看状态或道具是否更新,这样你就可以听到他们告诉人们不要像其他人提到的那样改变状态,

现在要实现任何反应组件,请记住,保持状态最小是您可以获得的最佳React实践,因此最好只为组件提供渲染所需的值。

onChange(event, i) {
 const target = event.target;
 const value = target.type === 'checkbox' ? target.checked : target.value;
 this.props.handleChange(this.props.blog, value)
}

render() {
  var { blog } = this.state                                                                                                                                                       
  return (                                                                                                                                                                          
     <div>
        {blog.name}
        <Checkbox
          checked={blog.checked}
          onChange={this.onChange}
          />
      </div>
    )
}

然后在您的父博客组件

handleChange(blog, value) {
 this.setState({
   blogs: [
    ...blogs,
    {...blog,  selected: value}
   ]
 })
}

答案 1 :(得分:0)

  

将反应状态视为不可变状态是否绝对必要?

取决于“绝对必要”的意思,但我认为如果the authors straight up tell you it's "wrong",在React中改变状态是一个非常糟糕的想法是安全的。如果你继续这样做的话,你会用脚射击自己。性能调优是一个原因,但另一个原因是,如果您不遵循React的API规则,例如无意中覆盖数据或以难以调试的方式破坏渲染,您将获得不可预测的行为。

React就是一个可预测的渲染周期:使用setState()进行状态更改,这将在未来的某个时刻以最新状态触发render()

你的第二个例子仍有问题。首先,您仍然通过设置blog来改变状态blog.checked = true。其次,您正在用newState替换整个状态。这是一个问题的处方,因为setState()只有安排一个补丁,所以你应该只替换你正在改变的道具 - setState({blogs})在你的情况下 - - 或者您可能与其他setState()的来电冲突。最后,如果您正在访问当前state,那么您应该使用回调表单(second example)来确保您正在使用的状态实际上是完全最新版本。

使用ES6对象传播你可以这样做:

this.setState((prevState, props) => {
  const {blogs} = this.state;
  return {
    blogs: [
      ...blogs.slice(0, i), 
      { ...blogs[i], selected: true }
      ...blogs.slice(i)
    ]
  };
});

或者使用map()只用索引替换一个元素:

this.setState((prevState, props) => {
  const {blogs} = this.state;
  return {
    blogs: blogs.map(
      (blog, index) => index == i ? { ...blog, selected: true } : blog
    )
  };
});