首页 > 解决方案 > React - SetState 处理程序方法

问题描述

我有一个具有以下情况的组件:

这是我在两个选择组件中选择两个团队(主队客队)时的两种方法

  const selectHomeTeamStat = evt => {
    const { value } = evt.target;
    setSelectedHomeOption(value);
    getStats(leagueId, value, 'home');
  };

  const selectAwayTeamStat = evt => {
    const { value } = evt.target;
    setSelectedAwayOption(value);
    getStats(leagueId, value, 'away');
  };

如您所见,我可以将此字符串参数“ Home ”和“ Away ”传递给getStats请求,以便区分并创建两种不同的状态

之后我意识到,我实际上需要将团队的状态名称作为参数传递给请求,而不是字符串“ Home ”和“ Away ”getStats

所以这改为

  const [selectedHomeName, setSelectedHomeName] = useState("");
  const [selectedAwayName, setSelectedAwayName] = useState("");

  const selectHomeTeamStat = evt => {
    const { value } = evt.target;
    const item = items.find(item => item.team_id == value);
    setSelectedHomeOption(value);
    setSelectedHomeName(item.name);
    console.log('Home Team Name:', selectedHomeName);
    getStats(leagueId, value, selectedHomeName);
  };

  const selectAwayTeamStat = evt => {
    const { value } = evt.target;
    const item = items.find(item => item.team_id == value);
    setSelectedAwayOption(value);
    setSelectedAwayName(item.name);
    console.log('Away Team name:', selectedAwayName);
    getStats(leagueId, value, selectedAwayName);
  };

item.name正确返回所选团队的名称,因此我也希望看到selectedHomeNameselectedAwayName声明,但在我的中console.log我看不到它

console.log('Home Team Name:', selectedHomeName); => Team Name:
console.log('Away Team Name:', selectedAwayName); => Away Name:

所以问题是,我做错了什么?我如何将这些状态传递到getStats事件处理程序内部以区分?

标签: javascriptreactjsevent-handlingreact-hookssetstate

解决方案


这是在调用它之前记录上一个值,因为这是定义函数时范围内的值。

如果您真的想记录最终将要(如setState异步)使其进入同一位置的状态的正确值,只需 log item.name

或者,如果您只想在该值已经处于状态后记录该值,那么您应该使用useEffect,将您想要响应的值传递给它deps

// We want React to call this function every time `selectedAwayName` changes:
useEffect(() => {
  console.log('Away Team name:', selectedAwayName);
}, [selectedAwayName]);

在这里你可以看到发生了什么以及如何useEffect修复它:

const App = () => {
  const [selectedHomeName, setSelectedHomeName] = React.useState('');
  const [selectedAwayName, setSelectedAwayName] = React.useState('');

  // When the component renders for the first time, this function is created,
  // and the `selectedHomeName` value that will log when called is the one
  // currently in scope, that is, an empty string.
  
  // When the component re-renders, a new function is created again with the
  // value currently in scope, which is the one we set previously. When changed
  // again, it will log the previous value, not the new one:
  
  const selectHomeTeamStat = ({ target }) => {
    setSelectedHomeName(target.textContent);
    console.log('PREVIOUS Home Team =', selectedHomeName);
  };

  const selectAwayTeamStat = ({ target }) => {
    setSelectedAwayName(target.textContent);
    console.log('PREVIOUS Away Team =', selectedAwayName);
  };
  
  // We are telling React to call this function every time `selectedHomeName` or
  // `selectedAwayName` change:
  React.useEffect(() => {
    console.log(`CURRENT TEAMS = ${ selectedHomeName } / ${ selectedAwayName }`);
  }, [selectedHomeName, selectedAwayName])
  
  return (<React.Fragment>
    <nav className="buttons">
      <button onClick={ selectHomeTeamStat }>Home Team 1</button>
      <button onClick={ selectHomeTeamStat }>Home Team 2</button>
      <button onClick={ selectAwayTeamStat }>Away Team 1</button>
      <button onClick={ selectAwayTeamStat }>Away Team 2</button>    
    </nav>
    
    <div>{ selectedHomeName } / { selectedAwayName }</div>
  </React.Fragment>);
}

ReactDOM.render(<App />, document.querySelector('#app'));
body,
button {
  font-family: monospace;
}

body, p {
  margin: 0;
}

#app {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
}

.buttons {
  display: flex;
  margin: 32px 0;
}

button {
  margin: 0 4px;
  padding: 8px;
  border: 2px solid black;
  background: transparent;
  cursor: pointer;
  border-radius: 2px;
}

.as-console-wrapper {
  max-height: 45px !important;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

考虑到这些更改,您现在可以使用useCallback,以便在每次重新渲染时不会重新创建这两个函数,因为它们不需要访问selectedHomeNameselectedAwayName不再需要:

const selectHomeTeamStat = React.useCallback(({ target }) => {
  setSelectedHomeName(target.textContent);
}, []);

const selectAwayTeamStat = React.useCallback(({ target }) => {
  setSelectedAwayName(target.textContent);
}, []);

推荐阅读