Can I use React.useCallback inside another React.useCallback?
<p>有一个渲染用户卡片的组件</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>
);
});
export default User;</pre>
</p>
<p>以及渲染用户卡的父组件</p>
<p>
<pre class="brush:js;toolbar:false;">import React from "react";
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);
return users.map((user) => {
const isSelected = selectedUserId === user.id;
return (
<User
{...user}
key={user.id}
isSelected={isSelected}
onClick={() => setSelectedUserId(user.id)}
/>
);
});
}
export default Application;</pre>
</p>
<p>任务是“选择用户后避免重新渲染其他用户卡”</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) => () => {
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>In this case, <code>React.useCallback</code> returns an anonymous function</p> with a new reference
<p><strong>Result: All user cards still re-render after each click</strong></p>
<p>I decided to wrap this anonymous function in <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>The problem is solved, but there is still one question, did I do it right? The React team says: <em>Don't call Hooks inside loops, conditionals, or nested functions</em> What side effects will I get? </p>
<p>Note do not touch the <code>user</code>component</p>