redux state更新不一致

图中默认红色区域是根据hostedLand这个数组来渲染的,初始length为1。图片描述

点击添加按钮后hostedLand的length为2
图片描述

添加按钮是没有问题的,可是我点击删除后全局state中的hostedLand的length会变小。但是渲染出来的是这样图片描述

并且控制台也不输出任何东西。
reducer:

const hostedLand = (state = [initState], action) => {
  switch(action.type) {
    // 增加
    case 'ADD_HOSTEDLAND':
      return [
        ...state,
        {...initState,
          id: action.id
        }
      ]
    // 删除
    case 'DELETE_LAND':
      state.splice(action.id, 1)
      return state
    .....
  }
}

组件相关代码:

import { addHostedLand } from '../actions'

const mapStateToProps = state = {
// 省略
}

const mapDispatchToProps = dispatch => {
    return {
        addHostedLand: () => dispatch(addHostedLand()),
        deleteLand: (...args) => dispatch(deleteLand(...args)),
    }
}
class HomeComponent extends Component {
    render(){
        const { hostedLand, addHostedLand } = this.props
        console.log(hostedLand)
        return (
            <div>
                {hostedLand.map(land => 
                    <OtherComponent {...this.props} key={land.id} id={land.id} />
                )}
                <button onClick={addHostedLand}>添加</button>
            <div>
        )
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(HomeComponent)

OtherCompoent:

...
render () {
    const {id, deleteLand } = this.props
    return () {
        .....
        <button onClick={() => deleteLand(id)}>删除<button>
        .....
    }
}
...
阅读 4.5k
3 个回答

在 reducer 中,删除的时候返回的是原数组,hostedLand 对象没有更新,仍为原对象,不会触发 re-render;增加的时候返回的是新数组,hostedLand 对象发生了改变,所以会触发 re-render。

state改变了,但UI没有变化,说明没有重新render; state又正好是一个数组,是引用类型,你的delete reducer又不是一个纯函数,没有返回一个新的数组,那么极有可能是shouldComponentUpdate导致。
所以,开始猜测:

  1. 你的组件extends PureComponent, 查看代码,发现并不是;并且也没写shouldComponentUpdate
  2. 你的组件的上级组件中,有PureComponent或者shouldComponentUpdate, 这我看不到代码,无法确认
  3. react-redux中的Provider没有inject新的store, 查看react-redux源码, 发现如下代码:
 this.setState(providerState => {
     // If the value is the same, skip the unnecessary state update.
     if (providerState.storeState === newStoreState) {
         return null
     }

     return { storeState: newStoreState }
 })

react-redux
综合上面猜测,我觉得是react-redux的Provider组件导致的,解决办法,遵守reducer是一个纯函数,每次都返回一个新的state; 或者魔改Provider源码(应该没人会这么做)

const hostedLand = (state = [initState], action) => {
  switch(action.type) {
    // 增加
    case 'ADD_HOSTEDLAND':
      return [
        ...state,
        {...initState,
          id: action.id
        }
      ]
    // 删除
    case 'DELETE_LAND':
      state.splice(action.id, 1)
      return {
          ...state
      }
    .....
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题