React - SetState 处理程序方法
React - SetState handler Method
我有一个组件存在以下情况:
当我select两支球队(主场,客场)在两个select时,这是两种方法组件
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
请求为了区分和创建然后两个不同的状态
在那之后我意识到我实际上需要 [=34= 而不是字符串 '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
returns 团队名称正确 selected 所以我希望看到 selectedHomeName
和 selectedAwayName
状态,但在我的 console.log
我没看到
console.log('Home Team Name:', selectedHomeName); => Team Name:
console.log('Away Team Name:', selectedAwayName); => Away Name:
所以问题是,我做错了什么?我如何将 这些状态 传递给事件处理程序中的 getStats
以进行区分?
这是在记录之前的值,因为它是函数定义时范围内的值,在调用它之前。
如果您真的想记录最终要记录的正确值(因为 setState
是异步的)使其进入同一位置的状态,只需记录 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
,这样这两个函数就不会在每次重新渲染时重新创建,因为它们不需要访问 selectedHomeName
或selectedAwayName
再:
const selectHomeTeamStat = React.useCallback(({ target }) => {
setSelectedHomeName(target.textContent);
}, []);
const selectAwayTeamStat = React.useCallback(({ target }) => {
setSelectedAwayName(target.textContent);
}, []);
console.log('Home Team Name:', selectedHomeName);
getStats(leagueId, value, selectedHomeName);
和
console.log('Away Team name:', selectedAwayName);
getStats(leagueId, value, selectedAwayName);
将始终是 selectedHomeName
和 selectedAwayName
的先前值。
这是因为您设置了将在事件处理程序中的下一次渲染时更新的值。
您应该使用 item.name
传递给 getStats
。您可以在渲染或其他地方使用 selectedHomeName
和 selectedAwayName
,或者作为 建议您可以使用 useEffect
来监听它们的变化
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:', item.name);
getStats(leagueId, value, item.name);
};
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:', item.name);
getStats(leagueId, value, item.name);
};
setState
是异步的。您正在记录当前渲染阶段的状态,更新后的值将仅在下一次渲染时可用。
要修复它,传递当前值 item.name
或使用 useEffect
const selectHomeTeamStat = (evt) => {
const { value } = evt.target;
setSelectedHomeOption(value);
}
useEffect(() => {
const item = items.find((item) => item.team_id == selectedHomeOption);
getStats(leagueId, selectedHomeOption, item.name);
}, [leagueId, items, selectedHomeOption]);
我有一个组件存在以下情况:
当我select两支球队(主场,客场)在两个select时,这是两种方法组件
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
请求为了区分和创建然后两个不同的状态
在那之后我意识到我实际上需要 [=34= 而不是字符串 '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
returns 团队名称正确 selected 所以我希望看到 selectedHomeName
和 selectedAwayName
状态,但在我的 console.log
我没看到
console.log('Home Team Name:', selectedHomeName); => Team Name:
console.log('Away Team Name:', selectedAwayName); => Away Name:
所以问题是,我做错了什么?我如何将 这些状态 传递给事件处理程序中的 getStats
以进行区分?
这是在记录之前的值,因为它是函数定义时范围内的值,在调用它之前。
如果您真的想记录最终要记录的正确值(因为 setState
是异步的)使其进入同一位置的状态,只需记录 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
,这样这两个函数就不会在每次重新渲染时重新创建,因为它们不需要访问 selectedHomeName
或selectedAwayName
再:
const selectHomeTeamStat = React.useCallback(({ target }) => {
setSelectedHomeName(target.textContent);
}, []);
const selectAwayTeamStat = React.useCallback(({ target }) => {
setSelectedAwayName(target.textContent);
}, []);
console.log('Home Team Name:', selectedHomeName);
getStats(leagueId, value, selectedHomeName);
和
console.log('Away Team name:', selectedAwayName);
getStats(leagueId, value, selectedAwayName);
将始终是 selectedHomeName
和 selectedAwayName
的先前值。
这是因为您设置了将在事件处理程序中的下一次渲染时更新的值。
您应该使用 item.name
传递给 getStats
。您可以在渲染或其他地方使用 selectedHomeName
和 selectedAwayName
,或者作为 useEffect
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:', item.name);
getStats(leagueId, value, item.name);
};
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:', item.name);
getStats(leagueId, value, item.name);
};
setState
是异步的。您正在记录当前渲染阶段的状态,更新后的值将仅在下一次渲染时可用。
要修复它,传递当前值 item.name
或使用 useEffect
const selectHomeTeamStat = (evt) => {
const { value } = evt.target;
setSelectedHomeOption(value);
}
useEffect(() => {
const item = items.find((item) => item.team_id == selectedHomeOption);
getStats(leagueId, selectedHomeOption, item.name);
}, [leagueId, items, selectedHomeOption]);