React Redux:即使 mapStateToProps 是,视图也没有更新

Posted

技术标签:

【中文标题】React Redux:即使 mapStateToProps 是,视图也没有更新【英文标题】:React Redux: View not getting updated even though mapStateToProps is 【发布时间】:2017-12-01 02:46:16 【问题描述】:

我的应用程序和商店

将 Redux 与 ReactJS 结合使用,我在 store 中保存了一个对象数组(称为结果)并调度对它进行排序和操作的操作。在 mapStateToProps 中,我返回了这个结果数组,它将结果呈现在视图的列表中。

// in Component file
export default class ResultList extends Component 
    constructor(props) 
        super(props);
        this.renderResults = this.renderResults.bind(this);
    

    renderResults(results) 
        return (
            results.map((result) => 
                return <AnotherComponent />
            )
        );
    

    render() 
        const  results  = this.props;
        return (
            <div>
                <ul>
                    this.renderResults(results)
                </ul>
            </div>
        )

// in Container Component file
const mapStateToProps = (state, ownProps) => 
    console.log('map state is triggered');
    return 
        results: state.results
    ;

问题

我发现 虽然我的 mapStateToProps 成功触发更新道具到我的类组件,出于某种原因视图仅在结果数组被操纵的第一次更新,但是不会更新商店的未来更新。 (请参阅下面的更新。这并不完全准确。)

我已经确定这个问题不是由于我的减速器中的变异状态(通常情况下);我已确认每次更新商店时都会运行 mapStateToProps(如 console.log 所示)。问题似乎在于从 mapStateToProps 返回的结果道具和实际呈现结果数组的视图之间,但我无法看到 Redux 在幕后所做的事情。

其他人遇到的最接近我遇到的问题似乎是这个,但我不知道此修复如何或是否适用于我对存储数组的使用:https://forums.meteor.com/t/the-state-is-correctly-mutated-and-returned-but-view-does-not-rerender/28840/5

任何帮助将不胜感激。谢谢。


更新

我很抱歉,但必须更正我上面的声明,即在商店中的结果第一次更新后视图没有进一步的更新。通过进一步的测试,我发现这并不完全正确。 仅当根据以下排序函数的案例 1 对结果数组进行排序时,视图才会更新。情况 2 和 3 是导致视图不更新的情况。 这可能是/可能不是必要的信息,但结果数组在 onClick 循环中按以下顺序按这 3 种情况排序:情况 1 , 案例 3, 案例 2。

// in reducer index.js file
case SORT_RESULTS:
    return 
        ...state,
        results: sortArr(state.results, state.sortType)
    ;

// sorting function
function sortArr(arr, sortType) 
    let newArr = [];
    switch (sortType) 
        case '1':
            for (let i = arr.length - 1; i >= 0; i--) 
                newArr.push(arr[i]);
            
            return newArr;
        case '2':
            newArr = arr;
            newArr.sort((a, b) => 
                return b.num - a.num;
            );
            return newArr;
        case '3':
            newArr = arr;
            newArr.sort((a, b) => 
                let id1 = a.id.toLowerCase();
                let id2 = b.id.toLowerCase();
                if (id1 < id2) 
                    return -1;
                
                if (id1 > id2) 
                    return 1;
                
                return 0;
            );
            return newArr;
        default:
            return arr;
    

【问题讨论】:

您尝试在mapStateToProps 中记录state.results 吗? 是的,我使用 redux-logger 中的 createLogger() 记录每次调度的状态。结果数组得到正确操作/更新。在 mapStateToProps 中执行 console.log(state.results) 会产生相同的结果。 你能退出componentWillRecieveProps(nextProps) console.log(nextProps.results)看看那里的道具有没有更新吗? componentWillReceiveProps 也只在结果存储的第一次更新时运行 我已经用澄清信息更新了帖子。我确信问题更多在于我对结果数组进行排序或返回新状态的方式。 【参考方案1】:

解决方案

这是罪魁祸首:newArr = arr。将其更改为newArr = arr.slice(),视图将在每次排序时更新。

可能的根本原因

至于为什么这个解决方案有效,我邀请其他人的观点。以下是我的想法:

根据https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Array/slice:

“slice() 方法将数组的一部分的浅拷贝返回到从开始到结束(不包括结束)选择的新数组对象中。”

使用newArr = arr复制结果数组似乎只是复制了指针(指向数组),实际上只是内存中的一个引用。如果这个说法是真的,那么Redux不会考虑状态完全改变了,因为它正在比较完全相同的指针(state.results),即使数组本身的实际数据已通过排序确认更改。通过slice() 复制一个全新的数组将涉及一个新的指针和数据,这将被检测为对 Redux 的底层更改。

【讨论】:

完全有同样的问题,让我发疯。感谢您的发帖! 是的。现在使用 lodash _.cloneDeep 没有问题 我在同样的问题上抛出了一个扩展运算符。感觉丑陋且效率低下,但它确实有效。

以上是关于React Redux:即使 mapStateToProps 是,视图也没有更新的主要内容,如果未能解决你的问题,请参考以下文章

React-Redux 应用程序真的可以像 Backbone 一样扩展吗?即使重新选择。在移动

找不到 react-redux 上下文值;请确保组件包含在 <Provider> 中,即使它已经包含在提供者中

当 redux 状态更新时,React 组件不更新

react-redux 类型文件中的 TypeScript 错误

使用 Electronjs/SerialPort 和 React/Redux 的数组绑定

为啥初始状态没有保留在 react-redux 中