【问题标题】:React state (redux) updates, interface does notReact 状态(redux)更新,界面没有
【发布时间】:2018-03-08 19:57:18
【问题描述】:

已解决

@jonahe 帮助我意识到我在组件状态中存储了陈旧的数据,导致 redux 和组件存储之间不匹配。

@vs1682 指出存储更新检查相对较浅,因此不应依赖于深层嵌套更改。


原问题:

我在 redux 中使用基于 promise 的操作并遇到以下问题:一旦我的状态更新(根据 redux 记录器验证),可视化组件不会反映这一点。

动作流程:

  1. 表单已提交(例如:生物属性更改)
  2. 智能组件触发动作调度
  3. 操作按预期工作并触发减速器
  4. 状态更新良好(反映在控制台的 redux 记录器中)
  5. 界面不反映变化(但状态肯定反映)

如上所述,我非常有信心我的行为和减速器都很好。我怀疑我忽略了 redux > 视觉流程中的某些内容。

以下是孤立的代码。我拿走了不相关的 jsx 等。

将状态映射到智能组件的 props:

export default connect( store => ( { 
    user: store.user ? true : false,
    contacts: store.contacts
} ) )( ContactList )

智能组件

<Person person = { this.state.showingperson } />

person 属性设置通过:

showPerson( e ) {
    e.preventDefault( )
    const showingperson = this.props.contacts.object[e.target.id]
    this.setState( { ...this.state, showingperson: showingperson } )
}

哑组件:

export const Person = ( { person } ) => {
    return <div id="persontable" className="backdrop">
                <div className = 'modal col l6 m12 s12 center'>
                    <p>Bio: { person.bio }.</p>
                </div>
            </div>
}

编辑:Reducer 代码:

从“时刻”导入时刻

const contactsReducer = ( state = { array: [], object: {} }, action ) => { 

    switch( action.type ) { 

        case 'UPDATE_FULFILLED':
        case 'GETALL_FULFILLED':
            // action.payload is an array of contacts resulting from a transformed firebase call
            return action.payload ? action.payload : state
        break

        case 'CLEAR_FULFILLED':
            return null
        break

        default:
            return state

     }

 }

 export default contactsReducer

【问题讨论】:

    标签: javascript reactjs redux react-redux


    【解决方案1】:

    使用下方评论部分的新信息进行编辑

    &lt;UserList /&gt; 还是&lt;Person /&gt; 组件没有显示更新的数据?因为如果&lt;Person /&gt; 没有更新考虑到它从内部状态的陈旧数据中获取数据,那将是有意义的:

    // this is used to set the internal component state
    const showingperson = this.props.contacts.object[e.target.id]
    // but after an update of the Redux state, this still points to the 
    // old (not updated) object in the internal state
    this.setState( { ...this.state, showingperson: showingperson } )
    

    所以内部状态将包含对旧对象的引用,直到再次执行 showPerson 函数。


    旧的错误答案

    这通常是由于 reducer 中的状态发生突变,导致 Redux 无法识别发生了应该重新渲染连接组件的更改。 (因为vs1682 提到的比较肤浅。)

    所以在你的减速器中,确保你没有做这样的事情:

    case UPDATE: {
      // mutation!
      state.contacts = action.payload;
      return state; 
    }
    

    但是有这样的东西

    case UPDATE: {
      // No mutation. Creating a new object!
      return {...state, contacts: action.payload};
      // or do the equivalent with Object.assign, 
      // Don't forget an empty object as first argument.
    }
    

    【讨论】:

    • reducer 是不可变的。我经历了通常的故障排除来仔细检查。在正确的不可变设置中,浅层检查仍然是一个问题吗?
    • 不应该。但无论如何我都会发布减速器代码以防万一。尤其是嵌套状态可能很棘手
    • 用代码编辑。希望我忽略了一些东西:)
    • 谢谢。 reducer 并不完全遵循约定,因为它似乎会根据操作返回完全不同的状态“形状”。 (例如,为什么 CLEAR_FULLFILLED 会返回 null,而不是回到 { array: [], object: {} } 的初始状态?)但我认为这可能会导致控制台出错,而不仅仅是不重新渲染。
    • &lt;UserList /&gt; 还是&lt;Person /&gt; 组件没有显示更新的数据?因为如果&lt;Person /&gt; 没有更新考虑到它从内部状态的陈旧数据中获取数据,那将是有意义的。 (直到您再次按下运行showPerson 函数。)。
    【解决方案2】:

    Connect 方法经过高度优化。 它比较从 mapStateToProps 和 mapDispatchToProps 方法返回的组合对象与它们之前的结果。 如果它们浅相等,则包装的组件将不会更新。

    要检查是否是这种情况,您可以将 componentWillReceiveProps 方法添加到包装的组件中,并检查您是否点击了此方法。

    【讨论】:

    • 啊,我想如果不是那么浅。是否建议手动触发重新渲染?
    • 如果希望您的组件无论如何渲染,那么您可以将{ pure: false } 作为第四个参数传递给连接。但这并不可取,因为您将失去 connect 提供的所有重度优化。每次商店更改时,您的包装组件都会重新渲染。
    • 嗯,是的,这听起来很不幸。有没有办法在我的调度成功后触发/强制优雅的重新渲染? (这是一个承诺,链接是微不足道的)
    • 另一种重新渲染组件的方法是传递一个新的ownPropsmapStateToProps 方法将 第二个参数 作为 ownProps,它只是传递给连接组件的道具。前任。 &lt;MyConnectedComponent newProp={someProp} /&gt;,您将获得 newProp 作为 mapStateToProps 方法的第二个参数。如果你自己的道具与前一个不同,你就可以走了。
    • 事实证明,在这种特殊情况下,问题是由于我自己在存储数据(组件状态)的位置上的愚蠢导致了过时的数据。请参阅对 OP 的编辑。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-09-08
    • 2019-03-10
    • 2021-03-08
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 2021-01-08
    相关资源
    最近更新 更多