как использовать React.memo с компонентом, содержащим дочерние элементы
Нужна помощь ~
У меня есть два компонента, и я обернул родительский элемент React.memo:
Ребенок
const Child = ()=> <div>I'm Child</div
export default Child
Родитель
const Parent = (props)=> <div>{props.children}</div>
export default React.memo(Parent)
Использование в приложении:
const App = () => {
const [count, setCount] = useState(0)
return(
<div>
<button onClick={()=>setCount(count+1)}></button>
<Parent>
<Child></Child>
</Parent>
</div>
)
}
Нажмите кнопку, результат:
Родительский компонент будет повторно отображен, поэтому памятка не работает, потому что ее дочерние элементы являются функциональным компонентом.
Итак, как я могу предотвратить повторную визуализацию?
Я знаю способ решить с помощью useMemo, но он уродлив и недружелюбен, у вас есть идеи получше?
const App = () => {
const [count, setCount] = useState(0)
const children = useMemo(()=><Child></Child>,[])
return(
<div>
<button onClick={()=>setCount(count+1)}></button>
<Parent>
{children}
</Parent>
</div>
)
}
4 ответа
const children = useMemo(()=><Child></Child>,[])
Это самый простой способ. С помощьюmemo(Child)
не будет работать, поскольку jsx фактически возвращает новый объект всякий раз, когда вы вызываете <Child />
. React.memo
по умолчанию просто используйте простое неглубокое сравнение, так что другого прямого способа решения нет. Вы можете создать свою собственную функцию, которая в конечном итоге будет поддерживать детей, и передать ееReact.memo(MyComp, myChildrenAwareEqual)
.
Оберните свой <Child />
с участием React.memo
:
const Child = ()=> {
console.log('render') // fires only once - on initial render
return <div>I'm Child</div>
}
const MChild = React.memo(Child);
const Parent = (props)=> <div>{props.children}</div>
const MParent = React.memo(Parent)
const App = () => {
const [count, setCount] = useState(0);
return(
<div>
<button onClick={()=>setCount(count+1)}>increment {count}</button>
<MParent>
<MChild></MChild>
</MParent>
</div>
)
}
render(<App />, document.getElementById('root'));
Двигаться
<Parent><Child/></Parent>
в отдельный компонент и вместо этого запомните этот компонент:
const Family = memo(() => <Parent><Child/></Parent>);
const App = () => {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count => count + 1)}>{count}</button>
<Family />
</>
)
}
const Memo = React.memo(({ children, value }) => {
return children
}, (prev, next) => prev.value === next.value)
А потом использовать это
function Title() {
const [count, setCount] = useState(0)
const onClick = () => {
setCount(c => c + 1)
}
const a = ''
return (
<>
<div onClick={onClick}>{count}</div>
<Memo value={a}>
<Child>
<Nothing2 a={a} />
</Child>
</Memo>
</>
)
}
Когда
a
изменения, дочерний рендеринг, в противном случае он выйдет из строя с предыдущим рендерингом.
Я обрисовываю рациональное решение в своем блоге https://javascript.plainenglish.io/can-usememo-skip-a-child-render-94e61f5ad981