当新元素添加到列表中时,我只想渲染新添加的元素,而不是重新渲染整个列表。 我尝试添加关键道具,但仍然所有元素都在渲染。 这是我的用例https://codesandbox.io/s/jovial-poincare-qcsvn?file=/src/App.js的示例代码,在这里我们可以在添加新元素时看 ...
提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供 中文繁体 英文版本 中英对照 版本,有任何建议请联系yoyou2525@163.com。
请考虑以下代码: https ://codepen.io/kyxey/pen/XWEWBRY
const { useRef, useState } = React; function App() { const inputRef = useRef(null); const [jobs, setJobs] = useState([]); const addJob = () => { const newJob = inputRef.current.value; if (newJob) { setJobs((prevJobs) => [...prevJobs, newJob]); } }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={addJob}>Add</button> <ul> {jobs.map((job) => { const listItem = job + " " + Math.random(); return <li key={listItem}>{listItem}</li>; })} </ul> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
在这个例子中,每当一个新项目被添加到列表中时,整个列表都会重新渲染。 您可以通过查看每个项目前面的随机数来判断这一点,该随机数会随着添加到列表中的每个新项目而改变。
现在我知道这个问题有一些重复,我把它们都读了。 但是他们都不能完全解决我的问题。
我的问题是:如何防止每次向其中添加新项目时重新呈现整个列表,而不使用任何形状和形式的memo
和useMemo
? 这意味着每当将新项目添加到列表中时,只会呈现新项目,而列表中的其他项目保持完全不变。 同样,我无法使用memo
或useMemo
来解决这个问题。
例如:
当前行为是这样的:
Test
Add
按钮 • Test 0.8025874545033296
AnotherTest
Add
按钮 • Test 0.4454662757698613 • AnotherTest 0.16319305763152014
预期的行为应该是这样的:
Test
Add
按钮 • Test 0.8025874545033296
AnotherTest
Add
按钮 • Test 0.8025874545033296 • AnotherTest 0.16319305763152014
更新:
这个问题是我在一次编程面试中问到的。 他们明确提到我不允许使用memo
或useMemo
,因为这些被认为是作弊! 现在我不知道他们为什么会这样想,但我敢肯定他们心中有一个特定的答案,这不是 React 应该如何表现的。
你说过:
这个问题是我在一次编程面试中问到的。 他们明确提到我不允许使用
memo
或useMemo
,因为这些被认为是作弊! 现在我不知道他们为什么会这样想,但我敢肯定他们心中有一个特定的答案,这不是 React 应该如何表现的。
一个合理的答案——很可能是他们所期待的——是这样的:“你可以这样做,但它只是无缘无故地重新发明memo
,并且通过做一些如此非标准和不寻常的事情,这将使代码难以理解和为下一个人维护。” 如果他们真的想在不使用这些东西的情况下看到解决方案,我建议您将它们从您可能考虑工作的地方列表中删除(如果您有任何选择)(我尊重您可能别无选择的事实;我很早就清楚地记得在我的职业生涯中)。 如果他们真的想要任何东西而不是回击(可以说即使他们正在寻找回击),那将是一个糟糕的面试问题,这可能表明工作场所不好。
但同样,从技术上讲,您可以通过将渲染的li
元素存储在其中(可能在Map
中)来使用 ref。 对我来说,这比你应该做的memo
更“作弊”,但是......这是一个例子:
const { useRef, useState } = React; // *** A means of having unique keys for jobs let nextJobId = 1; function App() { const inputRef = useRef(null); const [jobs, setJobs] = useState([]); const renderedJobs = useRef(new Map()); const jobLiElements = renderedJobs.current; const addJob = () => { // *** Make the jobs objects, not just strings, so the // same string can be used by more than one job and // so we can give the job a unique ID. const newJob = { id: nextJobId++, value: inputRef.current.value, }; if (newJob) { setJobs((prevJobs) => [...prevJobs, newJob]); } }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={addJob}>Add</button> <ul> {jobs.map((job) => { // *** Reuse li elements you already have if you have them, // adding new ones if you don't let li = jobLiElements.get(job); if (!li) { const listItem = job.value + " " + Math.random(); console.log(`Rendering li for ${job.value}`); // *** You can't use `listItem` as the key, since there's // _some_ chance of the same `li` having the same text and // random number. Use the job object instead. li = <li key={job.id}>{listItem}</li>; jobLiElements.set(job, li); } return li; })} </ul> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
但即使我向他们展示了这一点,我也会使用memo
向他们展示一个解决方案,并将随机值置于工作状态中,并谈论这样做的优势(尤其是正常的,预期的方式来做到这一点):
const { useRef, useState } = React; const JobItem = React.memo(({ job: { value, rand } }) => { const text = `${value} ${rand}`; console.log(`Rendering JobItem for "${text}"`); return <li>{text}</li>; }); // *** A means of having unique keys for jobs let nextJobId = 1; function App() { const inputRef = useRef(null); const [jobs, setJobs] = useState([]); const addJob = () => { // *** Make the jobs objects, not just strings, so the // same string can be used by more than one job, and so // we can assign it a unique ID to use as a key. // *** Assign the random number once, as part of the job. const newJob = { id: nextJobId++, value: inputRef.current.value, rand: Math.random(), }; if (newJob) { setJobs((prevJobs) => [...prevJobs, newJob]); } }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={addJob}>Add</button> <ul> {/* *** Now just use JobItem*/} {jobs.map((job) => ( <JobItem key={job.id} job={job} /> ))} </ul> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.