我是个新来的反应者,所以我想要的是,我有一个切换按钮来切换人员组件,还有一个驾驶舱组件。但是无论何时切换人员组件,我都不想总是重新渲染驾驶舱组件。
这是我的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组件仍在控制台中呈现...
Browser Console
答案 0 :(得分:1)
单击“切换人”,即可更改应用程序组件中的状态。 这样可以重新渲染App和Cockpit组件。
useEffect(() => {
console.log('[Cockpit.js] 2nd useEffect');
return () => {
console.log('[Cockpit.js] cleanup work in 2nd useEffect');
};
});
上面的代码将触发每个渲染,因为您没有提供依赖关系。 要解决此问题,您需要在上面的代码中添加一个依赖项。
答案 1 :(得分:1)
React.memo
默认情况下将对props
对象进行浅等式比较。这意味着它将检查道具中的每个顶级项目是否相等,如果其中任何一项发生更改,它将重新渲染。
当您单击人员切换按钮时,它将在您的showPersons
组件中更改App
,这也是传递给<Cockpit>
的一项道具。因此,即使使用React.memo
,它也会重新渲染。如果不进行渲染,就不会正确地添加或删除classes.Red
来更新Button类,因为这取决于showPersons
属性。
它与useEffect
内的cockpit
无关,后者只会在重新渲染后才被调用,而不会导致它首先重新渲染。
答案 2 :(得分:0)
自showPersons
更改以来,它会将其检测为更改的道具。
您可以在React.memo
中添加一个等于函数,该函数告诉作出反应何时考虑记忆陈旧:
// Will only rerender when someValue changes
export default React.memo(Cockpit, (oldProps, newProps) => oldProps.someValue === newProps.someValue)