React Hooks:组件在状态更新上落后了一步

时间:2020-03-04 19:07:17

标签: javascript reactjs react-hooks

我有一个对象数组,应该按用户定义的属性(在下拉列表中)进行排序。这是代码:

import React, {useState, useEffect} from 'react';

const repos = [
  {
    name: 'repo1',
    forks_count: 5,
    stargazers_count: 3,
    updated_at: 12
  },
  {
    name: 'repo2',
    forks_count: 7,
    stargazers_count: 2,
    updated_at: 17
  },
  {
    name: 'repo3',
    forks_count: 8,
    stargazers_count: 11,
    updated_at: 5
  }
];

function App() {
  const[data, setData] = useState([]);
  const[sortType, setSortType] = useState('stars');

  useEffect(() => {
    const sortRepos = (type) => {
      const types = {
          stars: 'stargazers_count',
          forks: 'forks_count',
          upd: 'updated_at'
      };
      const sortProperty = types[type]; 
      const sorted = repos.sort((a,b) => b[sortProperty] - a[sortProperty]);         
      setData(sorted);
    }; 

    sortRepos(sortType);
    }, [sortType]);


  return (
    <div className="App">
      <select onChange={(e) => setSortType(e.target.value)}>
        <option value='stars'>Stars</option>
        <option value='forks'>Forks</option>
        <option value='upd'>Updated</option>
      </select>

      <div >
      {data.map(repo => (
            <div key={repo.name}>
              <div>Name {repo.name}</div>
              <div>Forks {repo.forks_count}</div>
              <div>Stars {repo.stargazers_count}</div>
              <div>Update {repo.updated_at}</div>
            </div>
        ))} 
      </div>
    </div>
  );
}

但是问题在于,排序后的数据在更改下拉列表中的值后会重新向后退一步。

我在做什么错?我的猜测是问题在于比较对象,因为我已经测试过在数据变量中设置原始值,并且一切正常。但是没有对象。

1 个答案:

答案 0 :(得分:6)

问题是(间接地)您正在直接修改状态数据not allowed in React。您正在状态数组上调用sort,对数组进行排序。您需要将其复制并排序副本。您没有及时看到更新,因为您正在使用已经具有的相同数组调用setData,因此它忽略了该调用。

const sorted = [...repos].sort((a,b) => b[sortProperty] - a[sortProperty]);         
// −−−−−−−−−−−−^^^^^^^^^^

实时示例:

const {useState, useEffect} = React;

const repos = [
  {
    name: 'repo1',
    forks_count: 5,
    stargazers_count: 3,
    updated_at: 12
  },
  {
    name: 'repo2',
    forks_count: 7,
    stargazers_count: 2,
    updated_at: 17
  },
  {
    name: 'repo3',
    forks_count: 8,
    stargazers_count: 11,
    updated_at: 5
  }
];

function App() {
  const[data, setData] = useState([]);
  const[sortType, setSortType] = useState('stars');

  useEffect(() => {
    const sortRepos = (type) => {
      const types = {
          stars: 'stargazers_count',
          forks: 'forks_count',
          upd: 'updated_at'
      };
      const sortProperty = types[type]; 
      const sorted = [...repos].sort((a,b) => b[sortProperty] - a[sortProperty]);         
      setData(sorted);
    }; 

    sortRepos(sortType);
    }, [sortType]);


  return (
    <div className="App">
      <select onChange={(e) => setSortType(e.target.value)}>
        <option value='stars'>Stars</option>
        <option value='forks'>Forks</option>
        <option value='upd'>Updated</option>
      </select>

      <div >
      {data.map(repo => (
            <div key={repo.name}>
              <div>Name {repo.name}</div>
              <div>Forks {repo.forks_count}</div>
              <div>Stars {repo.stargazers_count}</div>
              <div>Update {repo.updated_at}</div>
            </div>
        ))} 
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>