[英]Why is React.memo not working with useEffect?
我对反应有点陌生,所以我想要的是,我有一个切换按钮来切换人员组件,我有一个驾驶舱组件。 但是每当我切换persons 组件时,我不想总是重新渲染cockpit 组件。
所以这是我的 Cockpit.js 组件文件。
import React, { useEffect } from 'react';
import classes from './Cockpit.css';
const cockpit = props => {
useEffect(() => {
console.log('[Cockpit.js] useEffect');
// Http request...
setTimeout(() => {
alert('Saved data to cloud!');
}, 1000);
return () => {
console.log('[Cockpit.js] cleanup work in useEffect');
};
}, []);
useEffect(() => {
console.log('[Cockpit.js] 2nd useEffect');
return () => {
console.log('[Cockpit.js] cleanup work in 2nd useEffect');
};
});
// useEffect();
const assignedClasses = [];
let btnClass = '';
if (props.showPersons) {
btnClass = classes.Red;
}
if (props.personsLength <= 2) {
assignedClasses.push(classes.red); // classes = ['red']
}
if (props.personsLength <= 1) {
assignedClasses.push(classes.bold); // classes = ['red', 'bold']
}
return (
<div className={classes.Cockpit}>
<h1>{props.title}</h1>
<p className={assignedClasses.join(' ')}>This is really working!</p>
<button className={btnClass} onClick={props.clicked}>
Toggle Persons
</button>
</div>
);
};
export default React.memo(cockpit);
这是我的 App.js
import React, { Component } from 'react';
import Persons from '../Components/Persons/Persons';
import classes from './App.css';
import Cockpit from '../Components/Cockpit/Cockpit'
class App extends Component {
constructor(props) {
super(props);
console.log("[App.js] constructor");
}
state = {
persons: [{id: "abc", name: "", age: 45},
{id: "azz", name: "", age: 56},
{id: "asq", name: "", age: 62}],
showPersons: false,
showCockpit: true
}
static getDerivedStateFromProps(props, state) {
console.log("[App.js] getDerivedStateFromProps", props)
return state;
}
componentDidMount() {
console.log('[App.js] componentDidMount')
}
shouldComponentUpdate(nextProps, nextState) {
console.log('[App.js] shouldCompoentUpdate');
return true;
}
componentDidUpdate() {
console.log('[App.js] componentDidUpdate')
}
deletePersonHandler = (i) => {
const persons = [...this.state.persons];
persons.splice(i, 1);
this.setState({persons: persons})
}
switchNameHandler = (newName) => {
this.setState({persons: [{name: newName, age: 50}, {name: "Aysha", age: 56}, {name: "Momma", age: 62}]})
}
nameSwitchHandler = (event, id) => {
const personIndex = this.state.persons.findIndex(p => {
return p.id === id;
})
const person = {...this.state.persons[personIndex]}
person.name = event.target.value;
const persons = [...this.state.persons]
persons[personIndex] = person;
this.setState({persons: persons})
}
togglePersonHandler = () => {
let doesChange = this.state.showPersons;
this.setState({showPersons: !doesChange})
}
render() {
console.log("[App.js] render");
let person = null;
if(this.state.showPersons) {
person = (<Persons
persons={this.state.persons}
clicked={this.deletePersonHandler}
changed={this.nameSwitchHandler} />
);
}
return (
<div className={classes.App}>
<button onClick={() => this.setState({showCockpit: false})}>Remove Cockpit</button>
{this.state.showCockpit ? (<Cockpit
title={this.props.appTitle}
showPersons={this.state.showPersons}
personsLength={this.state.persons.length}
clicked={this.togglePersonHandler} />) : null}
{person}
</div>
);
}
}
export default App;
但即使当我切换它时,驾驶舱组件中的 useEffect 仍然控制台登录浏览器控制台而不应该这样做。 我似乎找不到我做错了什么。
正如您在这张图片中看到的那样,驾驶舱中的 useEffect 组件仍然在控制台中呈现......
浏览器控制台
单击 Toggle Persons,您将更改 App Component 中的 state。 这会导致重新渲染 App 和 Cockpit 组件。
useEffect(() => {
console.log('[Cockpit.js] 2nd useEffect');
return () => {
console.log('[Cockpit.js] cleanup work in 2nd useEffect');
};
});
上面的代码将触发每个渲染,因为您没有提供依赖项。 要解决此问题,您需要向上述代码添加依赖项。
默认情况下, React.memo
将对props
object 进行浅层相等比较。 这意味着它将检查道具中的每个顶级项目是否相等,如果其中任何一个发生更改,它将重新渲染。
当您单击 people 切换按钮时,它将更改App
组件中的showPersons
,这也是您传递给<Cockpit>
的道具。 因此,即使使用React.memo
也会重新渲染。 如果它不会重新渲染,它就不会正确更新您的 Button class 添加或删除classes.Red
因为这取决于showPersons
道具。
它与cockpit
内的useEffect
无关,它只会在重新渲染后被调用,但不会导致它首先重新渲染。
由于showPersons
发生变化,它会将其检测为已更改的道具。
你可以在 React.memo 中添加一个相等的React.memo
来告诉 react 什么时候考虑 memoization stale:
// Will only rerender when someValue changes
export default React.memo(Cockpit, (oldProps, newProps) => oldProps.someValue === newProps.someValue)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.