【问题标题】:How can I use Redux to only update one instance of a component?如何使用 Redux 只更新组件的一个实例?
【发布时间】:2021-01-16 14:37:25
【问题描述】:

我正在尝试使用 Redux 来更新我的卡片组件以在点击时禁用和更改颜色。 Redux 可以很好地调度操作,但它会更新所有卡片,而不仅仅是被点击的卡片。每张卡片都有一个与之关联的对象,其中包含单词和值。该值是我想在单击时更改颜色的className

组件

const Card = ({ wordObj, updateClass, isDisabled, cardClass }) => {
    
    const showColor = (e) => {
        updateClass(wordObj);
        console.log(cardClass)
    };
    return (
        <button
            onClick={(e) => showColor()}
            disabled={isDisabled}
            className={cardClass}>
            {wordObj.word}
        </button>
    );
};


const mapStateToProps = (state) => ({
    cardClass: state.game.cardClass,
});
export default connect(mapStateToProps, { updateClass })(Card);

动作

export const updateClass = (obj) => (dispatch) => {
    console.log(obj)
    dispatch({
        type: UPDATE_CARD,
        payload: obj,
    });
};

减速器

const initialState = {
    words: [],
    cardClass: 'card',
    isDisabled: false,
};

export default function (state = initialState, action) {
    const { type, payload } = action;
    switch (type) {
        case SET_WORDS: {
            return {
                ...state,
                words: payload,
            };
        }   

        case UPDATE_CARD:
            return {
                ...state,
                isDisabled: true,
                cardClass: ['card', payload.value].join(' '),
            };

        default:
            return state;
    }
}```

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    您的所有卡片组件都在使用状态中的相同 cardClass 字段。当你在这一行修改它时:

    cardClass: ['card', payload.value].join(' ')
    

    所有使用此字段的卡片都会更新其类别。 isDisable 字段也是如此。

    您需要为您所在州的每张卡片创建一个对象。这是我的实现(未经测试):

    const initialState = {
        cards: []
    };
    
    export default function (state = initialState, action) {
        const { type, payload } = action;
        switch (type) {
            // create a card object for each word
            case SET_WORDS: {
                return {
                    ...state,
                    cards: payload.map(word => {
                        return { word: word, cardClass: "card", isDisabled: false }
                    })
                };
            }   
    
            case UPDATE_CARD:
                // here i'm using the wordObj.word passed as payload
                // to identify the card (i recommend to use an id field) 
                const cardIndex = state.cards.findIndex(card => card.word === payload.word);
                // get the current card
                const card = state.cards[cardIndex];
                // create an updated card object obeying the immutability principle
                const updatedCard = { ...card, isDisabled: true, cardClass: ['card', payload.value].join(' '), }
                return {
                    ...state,
                   cards: [
                       ...state.cards.slice(0, cardIndex), // cards before
                       updatedCard,
                       ...state.cards.slice(cardIndex + 1) // cards after
                   ]
                    
                };
    
            default:
                return state;
        }
    }
    

    【讨论】:

      【解决方案2】:

      您的mapStateToProps 选择了一个string,但是任何updateClass 上的字符串都发生了变化,这会导致您的所有卡片都更新,因为选择state.game.cardClass 会产生不同的值,这会触发新的渲染连接组件。

      也许你想要的是识别选择的东西,即每张卡的 id,并在 mapStateToProps 中使用该 id 选择以避免读取更改,因为现在发生的情况如下:

      卡 A[className="card A"] == 调度后 ==> mapStateToProps => [className="card B"]
      Card B[className="card A"] => dispatch('B') => mapStateToProps => [className="card B"]

      B 正在更新 A 和 B 的状态,这就是发生 extra 渲染的原因

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-04
        • 2015-06-13
        • 1970-01-01
        相关资源
        最近更新 更多