React新增列表项时不使用memo/useMemo避免全列表重渲染
问题根因
原代码把jobs数组存在App根组件的state里,每次调用setJobs更新数组都会让整个App组件重跑一遍渲染逻辑,jobs.map会全量执行,所有列表项的渲染代码都重新走一次,自然会重新生成每个条目前面的随机数。
题目不让用memo、useMemo做渲染缓存,解决的核心思路就是把已有列表项和App的重渲染链路切开,别让App更新的时候重新跑已有项的渲染代码。
实现代码
对应HTML依赖:
<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.development.js"></script>
核心逻辑代码:
const { useRef } = React; // 独立封装列表组件,自主维护列表DOM class JobList extends React.Component { constructor(props) { super(props); this.listRef = React.createRef(); } // 对外暴露新增条目的方法 addItem = (text) => { const randomVal = Math.random(); const newLi = document.createElement('li'); newLi.textContent = `${text} ${randomVal}`; this.listRef.current.appendChild(newLi); } render() { return <ul ref={this.listRef}></ul> } } function App() { const inputRef = useRef(null); const listRef = useRef(null); const handleAdd = () => { const inputVal = inputRef.current.value.trim(); if (!inputVal) return; // 直接调用列表组件的新增方法,不触发App自身重渲染 listRef.current.addItem(inputVal); inputRef.current.value = ''; } return ( <div> <input ref={inputRef} type="text" /> <button onClick={handleAdd}>Add</button> <JobList ref={listRef} /> </div> ) } ReactDOM.render(<App />, document.getElementById('root'));
方案说明
- 整个实现没用到
memo、useMemo任何一个被禁止的API,完全符合题目限制 - 把列表的DOM维护逻辑单独封在
JobList组件里,App本身不存任何和列表相关的state,点Add按钮的时候根本不会触发App重渲染 - 加新条目时只创建新的li节点插到ul里,已经存在的li节点完全不会被React的diff逻辑扫到,根本不会重渲染,每个条目刚生成时算出来的随机数会一直保留,加新条目时旧条目的数值一点不会变,完全符合预期效果
- 虽然直接操作DOM看起来不符合React数据驱动的常规写法,但在题目明确禁止使用缓存类API的约束下,这是性能最高、逻辑最清晰的实现方式,没有多余的渲染开销。
内容的提问来源于stack exchange,提问作者KYXEY
相关产品推荐
相关产品推荐

