React函数组件中Hook状态alreadyShown不更新问题求助
问题原因与解决方案
问题出在闭包陷阱:你通过getTableMembers生成<tr>元素并存在members状态里,这些元素的onClick回调捕获的是调用getTableMembers时的alreadyShown初始值(false)。之后不管状态怎么更新,这些回调里的alreadyShown永远是最初的false,所以每次点击只会执行else分支,没法切换状态。
解决方案1:不要把JSX存在状态里(推荐)
React里应该尽量把原始数据存在状态,渲染时再生成JSX,这样每次渲染都会生成新的回调,捕获最新的状态:
- 把存储JSX的
members状态改成存储原始成员数据:
// 替换原来的members状态 const [memberData, setMemberData] = useState([]);
- 修改
getTableMembers,只保存原始数据:
const getTableMembers = (result) =>{ setMemberData(result); }
- 在渲染表格时直接遍历
memberData生成行:
// 表格渲染部分 <table> <tbody> {memberData.map((member, index) => ( <tr key={member.id || index} className='table__content-table__row' onClick={() => showAttackOptions(member)}> <td>{index + 1}</td> <td>{member.NickName}</td> <td>{member.Power.Soldiers.Ammount}</td> <td>{member.alliance}</td> <td>Status</td> </tr> ))} </tbody> </table>
解决方案2:使用函数式更新获取最新状态
如果一定要保留原来的JSX存储方式,可以在更新状态时用函数式更新,这样能拿到最新的状态值,不受闭包影响:
const showAttackOptions = (prop) => { // 用prev获取最新的alreadyShown状态 setAlreadyShown(prevAlreadyShown => !prevAlreadyShown); setAttackDetails(prevDetails => { return !prevDetails ? <h1>{prop.NickName}</h1> : ''; }); }
另外,注意尽量不要用数组index作为key,如果member有唯一标识(比如id字段),用它作为key更稳妥,避免数组变化时组件复用导致的异常。
内容的提问来源于stack exchange,提问作者Amit Hadad
相关产品推荐
相关产品推荐

