Описание: я пытаюсь обновить состояние вложенного объекта. При обновлении вложенного объекта я вижу, что также вызывается метод рендеринга его родственного компонента.
Ожидаемое поведение: из всех статей, через которые я прошел, указывается, возвращать ли я новый объект только с обновленным вложенным объектом,реакция достаточно умна, чтобы отрисовывать только обновленный объект.
Пример:
reducer.tsx
// imports
const initialState = {
firstLevel: {
secondLevel: {
jobLevel: {
id: 'L52';
},
expectedSalary: {
amount: '100000';
}
}
}
}
export interface State {
firstLevel: {
secondLevel: {
jobLevel: {
id: string;
},
expectedSalary: {
amount: string;
}
}
}
}
export const mainState = (state: State = initialState, action) => {
switch(action.type) {
case 'NESTED_UPDATE':
return {
...state,
firstLevel : {
secondLevel: {
...state.firstLevel.secondLevel,
expectedSalary: {
amount: '120000'
}
}
}
}
}
}
Таким образом, в приведенном выше состоянии редукса я не изменяю состояние, чтобы начать с. Я возвращаю новый объект, который изменился в> firstLevel.secondLevel.expectedSalary
объекте. Пока firstLevel.secondLevel.jobLevel
объект не изменен.
Компоненты:
Main.tsx
// imports
class MainSection extends Component<> {
// constructor and more logic
render() {
return (
<div>
<JobLevel {...props.firstLevel.secondLevel} />
</div>
<div>
<ExpectedSalary
{...props.firstLevel.secondLevel}
updateSecondLevel={this.props.updatedSecondLevel} //I know its included in props, for readability
/>
</div>
}
}
export default MainSection;
MainContainer.jsx
import {connect} from 'react-redux';
import {SplitActions, CreateRuleState} from '../types';
import RuleSplitSection from '../components/RuleSplitSection';
import Actions from '../actions/RuleDrawerActions';
import {calculateSplitRuleLineWidth} from '../utils/RuleUtil';
export const mapStateToProps = (state) => {
return state;
};
export const mapDispatchToProps = dispatch => {
return {
updateSecondLevel: () => dispatch(Actions.updateSecondLevel())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Main as any);
Подкомпоненты: JobLevel.jsx
class JobLevel extends Component<> {
// constructor and more logic
render() {
return (
// debug point 1
<div>
// assume TextField is another redux util component which takes some props as below.
<TextField
value={this.props.jobLevel}
disabled // read only
/>
</div>
}
}
ExpectedSalary.jsx
class ExpectedSalary extends Component<> {
// constructor and more logic
updateExpectedSalarySecondLevel = evt => {
const expectedSalaryObj = {amount: evt.target.value}
this.props.updateSecondLevel('expectedSalary', expectedSalaryObj);
}
render() {
return (
// debug point 2
<div>
// assume TextField is another redux util component which takes some props as below.
<TextField
onChange={this.updateExpectedSalarySecondLevel}
value={this.props.expectedSalary}
/>
</div>
}
}
Сценарий: в приведенном выше случае, когда я что-то набираю в текстовом поле ExpectedSalary, я жестко кодирую значение в '120000' на данный момент. Мое понимание было, когда я обновил ExpectedSalary subobject
, реакция достаточно умна, чтобы просто перерисовать подкомпонент ExpectedSalary. Но от отладки я вижу, что он останавливается на debug point 1 and 2
.
Мне было интересно, почему ??? Теперь, чтобы избежать повторного рендеринга JobLevel, мне нужно использовать shouldComponentUpdate
и проверить глубокое копирование, как показано ниже:
shouldComponentUpdate(nextProps) {
return this.props.jobLevel.id !== nextProps.jobLevel.id;
}
Поэтому мои вопросы будут такими: 1. Переход в метод рендеринга JobLevel является частью реакции жизни-цикл? 2. Если да, нужно ли этого избегать? Это дорогой процесс?
Дайте мне знать, это comments
, если требуется дополнительная ссылка на код. Я исключил файл Actions
из простого кода от скуки ввода здесь.