在这种情况下如何重新渲染子组件?

How to re-render child component In this situation?

问题

如果我点击一个数字,数字应该会增加但不会增加。

如您所见,子组件没有重新渲染。 (如果我将 'li' 元素的键更改为 Math.random() 它工作正常。)

我该如何解决这种情况?

示例已发布在 https://codesandbox.io/s/p5q30rxk47

感谢阅读。

源代码

源码大致如下

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Parent from './Parent';

import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './redux';

const body = document.querySelector('body'),
      store = createStore(reducer);

ReactDOM.render(<Provider store={store}><Parent/></Provider>, body);

Parent.js

import React from 'react';
import { connect } from 'react-redux';
import Child from './Child';

class Parent extends React.PureComponent {
    get_numbers () {
        return this.props.numbers.map((number) => (
            <li key={number.id}>
                <span>number : </span><br/>
                <Child number={number} />
            </li>
        ));
    }

    render () {
        return (
            <ul>
                {this.get_numbers()}
            </ul>
        );
    }
}


function mapStateToProps(state) {
    return { numbers: state.numbers };
}

Parent = connect(mapStateToProps)(Parent);

export default Parent;

Child.js

import React from 'react';
import { connect } from 'react-redux';
import { increase_number } from './redux';

class Child extends React.PureComponent {
    render() {
        return (
            <span onClick={() => this.props.increase_number(this.props.number)}>{this.props.number.value}</span>
        );
    }
}

function mapDispatchToProps(dispatch) {
    return {
        increase_number: (number) => dispatch(increase_number({ number }))
    };
}

Child = connect(undefined, mapDispatchToProps)(Child);

export default Child;

redux.js

import { createAction, handleActions } from 'redux-actions';

export const increase_number = createAction('increase_number');

const initial_state = {
    numbers: [
        { id: 1, value: 1 },
        { id: 2, value: 2 },
        { id: 3, value: 3 }
    ]
};

export default handleActions({
    increase_number: (state, action) => {
        // console.log(action.payload.number.value);
        action.payload.number.value++;
        // console.log(action.payload.number.value);
        return { ...state, numbers: [...state.numbers] }
    }
}, initial_state);

要将值增加 1,您应该在 redux.js 文件中进行如下更改:

import { createAction, handleActions } from 'redux-actions';

export const increase_number = createAction('increase_number');

const initial_state = {
    numbers: [
        { id: 1, value: 1 },
        { id: 2, value: 2 },
        { id: 3, value: 3 }
    ]
};

export default handleActions({
    increase_number: (state, action) => {
        console.log(action.payload.number.value);
        // action.payload.numbers.value++;
        const numbers = [...state.numbers];
        numbers.push({
          id: action.payload.number.value++,
          value: action.payload.number.value++
        })
        // console.log(action.payload.number.value);
        return { ...state, numbers: numbers }
    }
}, initial_state);`

您需要获取 numbers 数组的深层副本,然后增加传入 payload 的数字的值,如下所示:

export default handleActions({
  increase_number: (state, action) => {
      let numberToModify = action.payload.number;

      // make a new array with new objects
      let newNumbers = state.numbers.map(n => ({ id: n.id, value: n.value }));

      // find the one that needs to be modified
      let existingNumber = newNumbers.find((number) => (number.id === numberToModify.id));
      if (existingNumber) {
        existingNumber.value++;
      }

      return { ...state, numbers: newNumbers };
  }
}, initial_state);

制作了一个工作示例here

您需要修改handleAction如下

export default handleActions({
increase_number: (state, action) => {
   action.payload.number.value++
   const currentNum = action.payload.number;

   let newLst = state.numbers.map((num) => {
     return num.id === currentNum.id ? {...action.payload.number} : num
    })

    return { ...state, numbers: newLst }
  }
}, initial_state);

这是工作示例 https://codesandbox.io/s/4jor55xz5w

稍微修改一下你handleActions

export default handleActions({
    increase_number: (state, action) => {
      action.payload.number.value++;

      const currNumber = action.payload.number;

      const numbers = state.numbers.map((num) => {
        return num.id === currNumber.id ? { ...action.payload.number } : num
      });

      return { ...state, numbers }
    }
}, initial_state);

这是因为键可以帮助您确定该元素是否 在虚拟 Dom 中进行比较时已更改, 所以如果元素的 id 相同, 即:第一里 1,第二里 2, dom 永远不会知道,因为元素会更新 基于虚拟 dom 的变化,即使值 正在改变 可能的解决方案是使用与 1、2、3 不同的 id,并更新 id 和值,以便 Dom 能够找出变化。

一个可能的破解可能是

increase_number: (state, action) => {
         //console.log(action.payload.number.value);
        action.payload.number.value++;
        action.payload.number.id--;
        //console.log(action.payload.number.value);
        return { ...state, numbers: [...state.numbers] }
    }

现在密钥每次都会用值更新,但应该 不会增加,因为它将是第二个 li 的相同键 dom 会给你一个错误 所以每次 1 到 2 它的 id 都会去——即 1-1 =0

here is the working Sample
https://codesandbox.io/s/mz6zy5rq28