<p>有一个渲染用户响应的组件</p>
<p>
从“react”导入React;
const User = React.memo(function({id, name, isSelected, ...other}) {
返回 (
{名称} - {isSelected && “已选择”}
);
});
导出默认用户;</pre>
</p>
<p>以及渲染用户卡的父组件</p>
<p>
从“react”导入React;
函数应用程序(){
const [用户,setUsers] = React.useState([
{id:1,名称:“John Doe #1”},
{id:2,名称:“John Doe #2”},
{id:3,名称:“John Doe #3”}
]);
const [selectedUserId, setSelectedUserId] = React.useState(null);
返回 users.map((user) => {
const isSelected = selectedUserId === user.id;
返回 (
<用户
{...用户}
密钥={用户.id}
已选择={已选择}
onClick={() =>; setSelectedUserId(user.id)}
>>
);
});
}
导出默认应用程序;
</p>
<p>任务是“选择用户后避免重新渲染其他用户卡”我尝试使用 React.useCallback
钩子,这是我的第一个实现</p>
<p>
从“react”导入React;
const User = React.memo(function({id, name, isSelected, ...other}) {
返回 (
{名称} - {isSelected && “已选择”}
;
);
});
function Application() {
const [users, setUsers] = React.useState([
{id: 1, name: "John Doe #1"},
{id: 2, name: "John Doe #2"},
{id: 3, name: "John Doe #3"}
]);
const [selectedUserId, setSelectedUserId] = React.useState(null);
const handleSelectUser = React.useCallback((userId) => () => {
setSelectedUserId(userId);
}, []);
return users.map((user) => {
const isSelected = selectedUserId === user.id;
return (
<User
{...user}
key={user.id}
isSelected={isSelected}
onClick={handleSelectUser(user.id)}
/>
);
});
}
export default Application;</pre>
</p>
<p>在这种情况下,<code>React.useCallback</code> 返回一个具有新引用的匿名函数</p>
<p><strong>结果:每次点击后所有用户卡仍重新呈现</strong></p>
<p>我决定将这个匿名函数包装在 <code>React.useCallback</code></p>
<p>
<pre class="brush:js;toolbar:false;">import React from "react";
const User = React.memo(function({id, name, isSelected, ...other}) {
return (
<div {...other}>
{name} - {isSelected && "Selected"}
</div>
);
});
function Application() {
const [users, setUsers] = React.useState([
{id: 1, name: "John Doe #1"},
{id: 2, name: "John Doe #2"},
{id: 3, name: "John Doe #3"}
]);
const [selectedUserId, setSelectedUserId] = React.useState(null);
const handleSelectUser = React.useCallback((userId) => {
return React.useCallback(() => {
setSelectedUserId(userId);
}, []);
}, []);
return users.map((user) => {
const isSelected = selectedUserId === user.id;
return (
<User
{...user}
key={user.id}
isSelected={isSelected}
onClick={handleSelectUser(user.id)}
/>
);
});
}
export default Application;</pre>
</p>
<p>问题解决了,但是还有一个问题,我做对了吗? React 团队说:<em>不要在循环、条件或嵌套函数内调用 Hooks</em>,我会得到什么副作用?</p>
<p>附注不要触摸<code>用户</code>组件</p>
解释为什么不能在钩子内部调用钩子(并期望它一致且可靠地工作)
为什么你不能在钩子内部调用钩子 - 去这里进行超深入的研究,其中的上下文比我在这个答案中需要提供的更多https://overreacted.io/why-do-hooks-rely-on-call-order/
您的解决方案之所以有效,是因为尽管“违反了规则”,但对挂钩的调用顺序始终相同......直到用户被添加或从状态中删除。
您绝对可以使用您所编写的解决方案。但是,在您需要 更改用户数量?
不,你不能在钩子内使用钩子。它可能“有效”,但 React 告诉你它无法可靠地工作,并且你做错了。必须在自定义钩子顶层组件的顶层调用钩子。
您的方向是正确的,但解决问题的方法是
div
元素上提供一些数据,以便让您知道点击了哪个用户元素。它看起来像这样: