react更新state后视图没有变化

新手上路,请多包涵
import React, { Component } from 'react'
import Clock from './Clock'

export default class DateCom extends Component {

  constructor(props) {
    super()
    this.customVal = [123, 345]
    this.state = {
      date: new Date(),
      stateCustom: this.customVal
    }
  }

  componentDidMount() {
    console.log('mounted')
    this.timer = setInterval(() => {
      this.setState({
        date: new Date()
      })
    }, 1000) 

    setInterval(() => {
      this.customVal.push(234)
    }, 1500);
  }

  componentWillUnmount() {
    clearInterval(this.timer)
  }

  render() {
    return (
      <div>
        <Clock date={this.state.date} />
        {this.state.stateCustom.map((item, index) => {
          return <span key={index}>{item}</span>
        })} {/*这样会更新*/}
        {this.state.stateCustom} {/* 这样不会更新 */}
        <br />
        {this.customVal}
      </div>
    )
  }
}

我是react新手,在学习state和生命周期的时候想试验下如果state中某个属性如果依赖某个变量,且在这个变量改变后不setState的话能不能让这个state变化

但是发现在我的这个例子中,render函数中如果直接使用stateCustom,那么即使改变它视图也不会变化,但如果是执行map那么视图会根据stateCustom的改变而变化,请问这是为什么呢!

感谢!!

阅读 9.1k
2 个回答

不会更新是假象。

// 实际上这个不影响 view 是否 render
{this.state.stateCustom}
// 事实上下面这个也从来没改变
{this.customVal}
// 你可以通过在 render 函数里添加 log 来看是否执行了 render 函数
render() {
    console.log('render')
    ...
    ...
}

如果要详细讲这个“为什么用 map 会更新而直接用数组不会”问题要涉及 tree diff 以及 react 是怎么 render 一个 element 的,但是我可以用简单点的说法描述这个。

map 会更新是因为 map 会返回一个新的数组,对于 react 来说它与之前的 element 并不一样,所以它会更新。

但是由于 {this.state.stateCustom} 或者 {this.customVal} 对于 react 来说它的值都是地址,由于这两个变量没有被重新赋值(地址没有改变),所以 react 会认为 这两个仍然是之前的 element ,就不会去更新它们。

你可以通过下面的方式观察一下区别

componentDidMount() {
  setInterval(() => {
    this.customVal.push(234);
    this.customVal = this.customVal.map(r => r);
  }, 1500);
}

render() {
    return (
        <div>
            {this.state.stateCustom}
            {this.customVal}
        </div>
    )
}
{this.state.stateCustom.map((item, index) => {
          return <span key={index}>{item}</span>
        })} {/*这样会更新*/}

更新的原因是因为this.state.stateCustomthis.customVal指向同一内存地址,你又设置了定时器对this.customVal执行push操作.所以在每次setState以后会根据this.state.stateCustommap出新的数据(当然这种做法是错误的,不应该直接修改this.state里面的值,而是返回一个新的值来代替)

不更新的原因应该就是上面我括号里导致的,具体原理不太确定.但是你把{this.state.stateCustom}改成{this.state.stateCustom.join('')}就会依然更新.

多说一句React把{this.state.stateCustom}传进来的数组强行转化成了字符串。(源码没研究,所以暂时说不明白到底怎么个转化方式)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题