繁体   English   中英

在不使用备忘录的情况下防止整个列表在 React 中添加项目时重新渲染

Preventing The Entire List Re-Render on Item Addition in React Without Using memo

提示:本站收集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>

在这个例子中,每当一个新项目被添加到列表中时,整个列表都会重新渲染。 您可以通过查看每个项目前面的随机数来判断这一点,该随机数会随着添加到列表中的每个新项目而改变。

现在我知道这个问题有一些重复,我把它们都读了。 但是他们都不能完全解决我的问题。

我的问题是:如何防止每次向其中添加新项目时重新呈现整个列表,而不使用任何形状和形式的memouseMemo 这意味着每当将新项目添加到列表中时,只会呈现新项目,而列表中的其他项目保持完全不变。 同样,我无法使用memouseMemo来解决这个问题。

例如:

当前行为是这样的:

  • 我在输入中输入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

更新:

这个问题是我在一次编程面试中问到的。 他们明确提到我不允许使用memouseMemo ,因为这些被认为是作弊 现在我不知道他们为什么会这样想,但我敢肯定他们心中有一个特定的答案,这不是 React 应该如何表现的。

1 个回复

你说过:

这个问题是我在一次编程面试中问到的。 他们明确提到我不允许使用memouseMemo ,因为这些被认为是作弊 现在我不知道他们为什么会这样想,但我敢肯定他们心中有一个特定的答案,这不是 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>

1 如何防止在 React 中添加新元素时重新渲染整个列表

当新元素添加到列表中时,我只想渲染新添加的元素,而不是重新渲染整个列表。 我尝试添加关键道具,但仍然所有元素都在渲染。 这是我的用例https://codesandbox.io/s/jovial-poincare-qcsvn?file=/src/App.js的示例代码,在这里我们可以在添加新元素时看 ...

2021-10-31 11:40:57 2 39   reactjs
3 页面阻止React重新渲染?

我有一个正常工作的React组件,可以在这里看到。 但是,将其嵌入内部页面时,尽管组件的计时仍然可以正常工作(请通过console.log确认),但不会重新渲染。 是否有任何可能阻止网页中的重新渲染? var Hello = React.createClass({ g ...

2016-07-20 17:38:55 0 41   reactjs
7 删除项目后如何使用类更新/重新呈现 React 列表

感谢您的支持。 我正在学习 React 并需要解决一个问题,即在从列表中删除项目后,我无法让 React 重新渲染。 首先,我想说我已经按照我找到的答案进行搜索,但仍然没有运气。 场景是我使用 React 从 API 中获取列表,并在同一个屏幕中呈现它,并使用一个表单来编辑和列出列表中每个项目的 ...

2021-07-20 14:43:04 2 30   reactjs
8 React i18next - 更改语言不会重新渲染使用 React.memo 记忆的组件

目前,我们正在为使用 I18nextProvider 并为集成应用程序传递 i18n 实例的 react 项目使用可重用的组件库。 其中一个应用程序使用使用 React.memo 的功能组件来处理不同的用例。 对于这些组件,当我们更改语言时,它不会触发重新渲染。 当我们手动进行更改时,它会反映在新的 ...

9 Vue - 如何在不重新渲染整个数组的情况下重新渲染特定的数组对象更改

我一直在寻找这个答案很长时间了。 最后发布它,因为我有一个与此相关的问题。 请检查下面的代码片段 方法 假设行是一个数组并且有 5 个元素 在某处我尝试更新行数组中的特定行。 在这种情况下索引 3 为什么 Vue 会重新渲染整个循环。 有没有办法只重新渲染特定索引 3 ? 这与更改 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM