首页 > 解决方案 > 在 React 中引用前一个状态时在 setState 中使用回调

问题描述

我正在对表格进行排序,它应该按字母顺序对列进行排序,按字母顺序反转,并在每次调用该方法时返回原始形式。

这是我的代码:

export default class GenericTable extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      otherStudd: '',
      currentSort: 'default',
          rows: this.props.rows, // I receive the rows data on props        
       };
    }

  onSortChange = index => {
    const sortMap = {
      default: 'up',
      up: 'down',
      down: 'default',
    };

    const { currentSort, currentIndex } = this.state;

    const nextSort = currentIndex === index ? sortMap[currentSort] : 'default';

    const newRows = [...this.state.rows]; // line 40 - here is the error

    switch (nextSort) {
      case 'up':
        newRows.sort((a, b) => (a.cells[index] <= b.cells[index] ? -1 : 1));
        break;
      case 'down':
        newRows.sort((a, b) => (b.cells[index] <= a.cells[index] ? -1 : 1));
        break;
    }

    this.setState({
      rows: newRows,
      currentSort: nextSort,
      currentIndex: index,
    });
  };

...

}

我认为代码看起来正确,但我收到一条 es-lint 错误消息:

 Line 40:25:  Use callback in setState when referencing the previous state  react/no-access-state-in-setstate

它应该做一个回调函数,但我不知道如何让它工作。

有任何想法吗?

标签: javascriptreactjsreact-nativeecmascript-6setstate

解决方案


将 props 分配给 state 并从那里使用它们是一种 React 反模式(您可以在此处阅读有关它的更多信息)。

当您尝试实现的场景需要时,推荐的方法是创建一个完全受控的组件,或者在这种情况下,一个部分受控的组件,不仅rows从道具使用,而且对它们的任何转换也通过道具(在这种情况下,排序)。

下面的代码片段演示了手头问题的简化版本。我们创建了一个Parent存储rows其状态的组件,并提供了一个执行排序的方法。然后它呈现一个完全受控的Child组件,该组件不需要拥有自己的状态,而是接收行以及它的排序器功能作为道具。

sortRows方法说明了如何使用setState回调,与提供状态对象相比,该回调提供了在状态上产生更一致的结果的好处。

class Child extends React.PureComponent {
    render() {
        const { rows, sortRows } = this.props;
        return (
            <div>
                <ul>{ rows.map((row, i) => (<li key={ i }>{ row }</li>)) }</ul>
                <button onClick={ () => { sortRows(true) }}>Sort Ascending</button>
                <button onClick={ () => { sortRows(false) }}>Sort Descending</button>
            </div>
        );
    }
}
class Parent extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            rows: ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter']
        };
    }

    sortRows = (isSortAscending) => {
        this.setState((prevState) => ({
            rows: prevState.rows.slice().sort((a, b) => {
                if (a < b) return -(isSortAscending ? 1 : -1);
                if (a > b) return (isSortAscending ? 1 : -1);
                return 0;
            })
        }));
    }

    render() {
        return <Child rows={ this.state.rows } sortRows={ this.sortRows } />;
    }
}
ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>


推荐阅读