從「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((用戶) => { const isSelected = selectedUserId === user.id; 返回 ( <使用者 {...使用者} 密鑰={用戶.id} 已選擇={已選取} onClick={() =>; setSelectedUserId(user.id)} >> ); }); } 導出預設應用程式;</pre> </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>
P粉8100506692023-09-02 12:43:37
為什麼你不能在鉤子內部調用鉤子- 去這裡進行超深入的研究,其中的上下文比我在這個答案中需要提供的更多https://overreacted.io/why-do-hooks -rely-on-call-order/
#您的解決方案之所以有效,是因為儘管“違反了規則”,但對掛鉤的調用順序始終相同......直到用戶被添加或從狀態中刪除。
您絕對可以使用您所寫的解決方案。但是,在您需要 更改使用者數量?
不,你不能在鉤子內使用鉤子。它可能“有效”,但 React 告訴你它無法可靠地工作,並且你做錯了。必須在自訂鉤子頂層元件的頂層呼叫鉤子。
您的方向是正確的,但解決問題的方法是
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); // this callback is referentially stable - it doesn't change between renders because it has no dependencies const handleSelectUser = React.useCallback((e) => { setSelectedUserId(+e.target.getAttribute('data-userid')); }, []); return users.map((user) => { const isSelected = selectedUserId === user.id; return ( <User {...user} data-userid={user.id} <- this line key={user.id} isSelected={isSelected} onClick={handleSelectUser} /> ); }); }