【问题标题】:React redux - parent state changing, but child components not re-renderingReact redux - 父状态改变,但子组件不重新渲染
【发布时间】:2018-08-21 13:19:30
【问题描述】:

我只是想学习使用 redux,我有一个非常简单的计数器列表组件,它有一个子计数器组件的列表。

我在计数器上有一个 onIncrement 操作,我想在单击时增加计数。

当我单击增量时,它会更新父状态,但子计数器不会更新。如果我浏览然后返回列表,它确实呈现正确,这在我看来意味着状态已更新。

这是我的代码:

计数器组件

import React, { Component } from "react";
import { connect } from 'react-redux';
import { incrementCounter } from '../../actions/counterActions';
import PropTypes from 'prop-types';

class Counter extends Component {
    render() {
        return <div className="m-2">
            <b>{this.props.counter.count}</b>
            <button className="btn btn btn-secondary btn-sm m-2" onClick={() => { this.onIncrement(this.props.counter) }}>Increment</button>
        </div>;
    }

    onIncrement(counter) {
        this.props.incrementCounter(counter);
    }
}

const mapStateToProps = state => ({
})

Counter.propTypes = {
    incrementCounter: PropTypes.func.isRequired,
}

export default connect(mapStateToProps, { incrementCounter })(Counter);

计数器列表组件

import React, { Component } from "react";
import { RouteComponentProps } from "react-router";
import { CounterContext } from "../../contexts/context.js";
import Counter from "./Counter";
import { NewItem } from "./NewItem";
import ItemContainer from "../layout/ItemContainer";

import { connect } from 'react-redux';
import { getCounters } from '../../actions/counterActions';
import PropTypes from 'prop-types';

class CounterList extends Component {
    componentWillMount() {
        if (this.props.counters.length == 0) {
            this.props.getCounters();
        }
    }

    render() {
        const counterItems = this.props.counters.map(counter => <Counter key={counter.id} counter={counter} />);
        return <div>{ counterItems }</div>;
    }
}

const mapStateToProps = state => ({
    counters: state.counters.items
})

CounterList.propTypes = {
    getCounters: PropTypes.func.isRequired,
    counters: PropTypes.array.isRequired
}

export default connect(mapStateToProps, { getCounters })(CounterList);

反制措施

import { GET_COUNTERS, INCREMENT_COUNTERS } from '../actions/types';

export const getCounters = () => dispatch => {
    const counters = [{ id: 1, count: 4 }, { id: 2, count: 3 }, { id: 3, count: 0 }];
    // this could be API call to get initial counters
    console.log('In GetCounters', GET_COUNTERS);

    return dispatch({
        type: GET_COUNTERS,
        payload: counters
    })
}

export const incrementCounter = (counter) => dispatch => {
    // this could be API call to get initial counters
    counter.count++;

    return dispatch({
        type: INCREMENT_COUNTERS,
        payload: counter
    })
}

计数器减速器

import { GET_COUNTERS, INCREMENT_COUNTERS } from '../actions/types';

const initialState = {
    items: []
}

export default function (state = initialState, action) {
    console.log(action.type);
    switch (action.type){
        case GET_COUNTERS:
            return {
                ...state,
                items: action.payload
            };
        case INCREMENT_COUNTERS:
            var counter = action.payload;

            const counters = [...state.items];
            const index = counters.findIndex(x => x.id == counter.id);
            counters[index] = counter;

            return {
                ...state,
                items: counters
            };
        default: 
            return state;
    }
}

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    我猜问题可能是您将更新后的 count 值的相同旧计数器对象分配给您的 counters[index],因此 Counter 组件没有看到变化。这可能是因为 shouldComponentUpdate 进行了浅层检查,并且对 counter 道具的对象引用保持不变,并且您的组件不会重新渲染。

    如果您在您的状态下使用多维数组或嵌套对象,则应该使用深度克隆。

    建议使用 Immutable.js 之类的库,以确保您的 reducer 保持纯净。

    case INCREMENT_COUNTERS:
      var counter = action.payload;
    
      const counters = JSON.parse(JSON.stringify(state.items)); //this creates a deep copy
      const index = counters.findIndex(x => x.id == counter.id);
      counters[index].count = counter.count;
    
      return {
        ...state,
        items: counters
      };

    【讨论】:

    • 非常感谢,原来是这个问题,将计数器设置为深拷贝以及专门设置计数使计数器工作。非常感谢您的回答
    【解决方案2】:

    您没有将状态映射到道具,例如:

    function mapStateToProps = state => {
      return { count: state.count }; 
    }
    

    这会将 redux 中反映计数器更改的状态映射到要显示当前计数的组件的 props。 希望这会有所帮助!

    【讨论】:

    • 对不起,我需要在哪里添加这个?我在计数器组件中尝试过,但没有成功
    • 在计数器组件的 mapStateToProps 函数中。
    • 该州没有计数属性,只是一个计数器列表...我尝试了以下操作,它确实将其映射到正确的计数器,但这仍然没有更新。 .. const mapStateToProps = (state, ownProps) => ({ counter: state.counters.items.find(counter => counter.id == ownProps.id) });
    【解决方案3】:

    您可以尝试将componentWillReceiveProps 放入您的Counter 组件中,并检查每次单击按钮时是否获得新的counter 属性。

    【讨论】:

    • 好的,所以只用 console.log("componentWillReceiveProps", nextProps);而且它根本没有达到这个目标
    • 放一个额外的道具,比如&lt;Counter key={counter.id} counter={counter} aa={counter.count} /&gt; 看看。我认为这是因为您的 store.items 是一个可变对象列表,而 INCREMENT_COUNTERS 中的 counter++ 仍然修改同一个对象而不是返回一个新对象,这就是 react update 没有选择它的原因。
    猜你喜欢
    • 2018-12-31
    • 1970-01-01
    • 2020-12-30
    • 2018-12-31
    • 2019-09-21
    • 2020-06-26
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多