[英]react memoize using React.memo
I Try not to Rerender Persons Component When ShowCockpit State Changes In MainAssignment Component.当 MainAssignment 组件中的 ShowCockpit State 更改时,我尽量不重新渲染Persons组件。 Like when i do in Cockpit Component, it doesn't rerender When Persons state change.
就像我在 Cockpit Component 中所做的那样,当 Persons state 更改时,它不会重新呈现。 In This Case We Have 3 Components MainAssignment Component [parnt], Cockpit Component [child], Persons Component [child].
在这种情况下,我们有 3 个组件 MainAssignment 组件 [parnt]、Cockpit 组件 [child]、Persons 组件 [child]。
/********************************************************/
/*** MainAssignment Component ***/
import React, { useCallback, useState } from 'react';
import Persons from './persons';
import Coockpit from './cockpit';
const MainAssignment = () => {
// All State
const [persons, setPersons] = useState([
{ id: '1', name: 'mustafa', age: 24 },
{ id: '2', name: 'ahmed', age: 25 },
{ id: '3', name: 'saad', age: 26 },
]);
const [showPersons, setShowPersons] = useState(true);
const [showCoockpit, setShowCoockpit] = useState(true);
const togglePersonHandler = useCallback(() => {
setShowPersons(!showPersons);
}, [showPersons]);
// change name in specific object in persons state
const nameChangeHandler = (e, id, personIndex) => {
let newPersons = [...persons];
let person = { ...newPersons[personIndex] };
person.name = e.target.value;
newPersons[personIndex] = person;
setPersons(newPersons);
};
// delete object from persons state
const deletePersonHandler = (personIndex) => {
let newPersons = [...persons];
newPersons.splice(personIndex, 1);
setPersons(newPersons);
};
// Main Render
return (
<>
<button
onClick={() => {
setShowCoockpit((prev) => !prev);
}}
>
remove Coockpit
</button>
{showCoockpit ? (
<div style={{ border: '1px solid' }}>
<Coockpit clicked={togglePersonHandler} personsLength={persons.length} showPersons={showPersons} />
</div>
) : null}
{showPersons ? <Persons persons={persons} clicked={deletePersonHandler} changed={nameChangeHandler} /> : null}
</>
);
};
export default MainAssignment;
/********************************************************/
/*** Cockpit Component ***/
/********************************************************/
/*** Cockpit Component ***/
import React, { useRef } from 'react';
const Cockpit = ({ clicked }) => {
let toggleBtnRef = useRef(null);
console.log('render => Cockpit');
return (
<div>
<h1>hi i'm a main assin from cockpit</h1>
<button className="toggle-persons" onClick={clicked} ref={toggleBtnRef}>
toggle persons
</button>
</div>
);
};
// in Cockpit i use React.memo and it work
export default React.memo(Cockpit);
/********************************************************/
/*** Persons Component ***/
import React, { useEffect, useRef } from 'react';
import Person from './person';
const Persons = ({ persons, clicked, changed }) => {
console.log('render => personssss');
const mainRef = {
allInputPersonRef: useRef([]),
};
return (
<>
{persons?.map((person, idx) => (
<Person
key={idx}
name={person.name}
age={person.age}
position={idx}
index={idx}
ref={mainRef}
click={() => {
clicked(idx);
}}
changed={(e) => {
changed(e, person.id, idx);
}}
/>
))}
</>
);
};
// in Persons i use React.memo and it doesn't work
export default React.memo(Persons);
/********************************************************/
/*** Person Component ***/
import React from 'react';
const Person = React.forwardRef((props, ref) => {
const { allInputPersonRef } = ref;
// value of props
const { name, age, click, changed, children, index } = props;
return (
<div>
<p onClick={click}>
i'm {name} and i'm {age} years old
</p>
<p> i'am props children: {children}</p>
<input type="text" onChange={changed} value={name} ref={(el) => (allInputPersonRef.current[index] = el)} />
<button onClick={click}>delete this person</button>
</div>
);
});
export default Person;
React.memo
can prevent children from rerendering when the parent component rerenders. React.memo
可以防止子组件在父组件重新渲染时重新渲染。
It compares (by reference) each previous and next prop.它比较(通过引用)每个前一个和下一个道具。 When one of them is different React will rerender the child normally.
当其中一个不同时,React 将正常重新渲染孩子。
In your case you are always passing new function to changed
prop在您的情况下,您总是将新的 function 传递给
changed
的道具
const nameChangeHandler = (e, personIndex) => {
let newPersons = [...persons];
let person = { ...newPersons[personIndex] };
person.name = e.target.value;
newPersons[personIndex] = person;
setPersons(newPersons);
};
How to avoid this?如何避免这种情况?
Make sure that nameChangeHandler
is the same function each time you need to rerender and you don't want to rerender the Person
component.确保每次需要重新渲染并且不想重新渲染
Person
组件时nameChangeHandler
与 function 相同。 https://reactjs.org/docs/hooks-reference.html#usecallback https://reactjs.org/docs/hooks-reference.html#usecallback
const nameChangeHandler = useCallback((e, personIndex) => {
setPersons((persons) => {
let newPersons = [...persons];
let person = { ...newPersons[personIndex] };
person.name = e.target.value;
newPersons[personIndex] = person;
return newPersons
});
}, []);
Similarly you should memorize deletePersonHandler
function同样,您应该记住
deletePersonHandler
andler function
const deletePersonHandler = useCallback((personIndex) => {
setPersons((persons)=>{
let newPersons = [...persons];
newPersons.splice(personIndex, 1);
return newPersons
});
}, []);
using useCallback on togglePersonHandler and deletePersonHandler在 togglePersonHandler 和 deletePersonHandler 上使用 useCallback
let newPersons = [...persons];
let person = { ...newPersons[personIndex] };
person.name = e.target.value;
newPersons[personIndex] = person;
setPersons(newPersons);
}, []);
const deletePersonHandler = useCallback((personIndex) => {
let newPersons = [...persons];
newPersons.splice(personIndex, 1);
setPersons(newPersons);
}, []);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.