如何在更新状态的情况下使用 getDerivedStateFromProps?
How to use getDerivedStateFromProps in an update state situation?
我对代码的重构感到困惑。
我的组件是这样工作的 ==> 我将来自父组件的传入道具设置为子组件的状态。然后我就可以在组件中进行更新状态操作了。
这是我的 UNSAFE_componentWillReceiveProps
函数:
UNSAFE_componentWillReceiveProps = (nextProps) => {
if (nextProps
&& nextProps.actionToEdit
&& nextProps.actionToEdit.statement
) {
const regex = /@\w+/g;
const found = nextProps.actionToEdit.statement.match(regex);
this.setState({
parameters: found
});
}
};
这是我的 getDerivedStateFromProps
功能:
static getDerivedStateFromProps(
nextProps: ICustomActionModalProps,
prevState: ICustomActionModalState
) {
if (nextProps
&& nextProps.actionToEdit
&& nextProps.actionToEdit.statement
) {
const regex = /@\w+/g;
const found = nextProps.actionToEdit.statement.match(regex);
return {
parameters: found
};
}
return null;
}
这是我的 onChange 函数:
onChange = (newValue, e) => {
const regex = /@\w+/g;
const found = newValue.match(regex);
this.setState({ parameters: found });
};
当 onChange 起作用时,我意识到了一些事情。
==> 如果我使用 UNSAFE_componentWillReceiveProps
,状态更新完美。因为当onChange函数每次都起作用时UNSAFE_componentWillReceiveProps
不起作用。
然而,
==> 如果我使用 getDerivedStateFromProps
,状态会更新为旧的道具。因为当 onChange 函数每次都起作用时 getDerivedStateFromProps
也起作用。
我只希望我的 getDerivedStateFromProps
功能能够像我的旧 UNSAFE_componentWillReceiveProps
功能一样工作。
我该怎么做?
谢谢
您所描述的 problem 可以通过使您的 Component
完全受控或完全不受控但使用钥匙来解决。
第一种方法可能如下所示:
// --- parent component: Parent.tsx
import { Child } from "./Child";
export class Parent extends React.Component<{}, { counter: number }> {
state = { counter: 0 };
render() {
return (
<div>
<div>
<button onClick={() => this.setState(({ counter }) => ({ counter: counter + 1 }))}>increase counter</button>
</div>
<Child
parentCounter={this.state.counter}
setParentCounter={(n) => this.setState({ counter: n })}
/>
</div>
);
}
}
// --- child component : Child.tsx
type Props = { parentCounter: number; setParentCounter: (n: number) => void };
export class Child extends React.Component<Props> {
render() {
const { parentCounter, setParentCounter } = this.props;
return (
<>
<div>parent counter: {parentCounter}</div>
<button
onClick={() => {
setParentCounter(parentCounter + 1);
}}
>
increase parent counter
</button>
</>
);
}
}
因此,不存在两种独立的状态:一种在父组件中,另一种在子组件中。唯一的状态存在于父组件中,子组件有 setter 属性,它可以用来改变父组件的状态。
第二种方法(带键的不受控制的组件)使用这样一个事实,即当 key
更改子组件时,它会从头开始重新呈现并失去其内部状态:
// --- Parent.tsx
import { Child } from "./Child";
export class Parent extends React.Component<{}, { counter: number }> {
state = { counter: 0 };
render() {
const { counter } = this.state;
return (
<div>
<div>parent counter: {counter}</div>
<div>
<button
onClick={() =>
this.setState(({ counter }) => ({ counter: counter + 1 }))
}
>
increase parent counter
</button>
</div>
<Child parentCounter={counter} key={`child-key-${counter}`} />
</div>
);
}
}
// --- Child.tsx
type Props = { parentCounter: number };
type State = { childCounter: number };
export class Child extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { childCounter: props.parentCounter };
}
render() {
return (
<>
<div>child counter {this.state.childCounter}</div>
<button
onClick={() => {
this.setState(({ childCounter }) => ({
childCounter: childCounter + 1
}));
}}
>
increase child counter
</button>
</>
);
}
}
我对代码的重构感到困惑。
我的组件是这样工作的 ==> 我将来自父组件的传入道具设置为子组件的状态。然后我就可以在组件中进行更新状态操作了。
这是我的 UNSAFE_componentWillReceiveProps
函数:
UNSAFE_componentWillReceiveProps = (nextProps) => {
if (nextProps
&& nextProps.actionToEdit
&& nextProps.actionToEdit.statement
) {
const regex = /@\w+/g;
const found = nextProps.actionToEdit.statement.match(regex);
this.setState({
parameters: found
});
}
};
这是我的 getDerivedStateFromProps
功能:
static getDerivedStateFromProps(
nextProps: ICustomActionModalProps,
prevState: ICustomActionModalState
) {
if (nextProps
&& nextProps.actionToEdit
&& nextProps.actionToEdit.statement
) {
const regex = /@\w+/g;
const found = nextProps.actionToEdit.statement.match(regex);
return {
parameters: found
};
}
return null;
}
这是我的 onChange 函数:
onChange = (newValue, e) => {
const regex = /@\w+/g;
const found = newValue.match(regex);
this.setState({ parameters: found });
};
当 onChange 起作用时,我意识到了一些事情。
==> 如果我使用 UNSAFE_componentWillReceiveProps
,状态更新完美。因为当onChange函数每次都起作用时UNSAFE_componentWillReceiveProps
不起作用。
然而,
==> 如果我使用 getDerivedStateFromProps
,状态会更新为旧的道具。因为当 onChange 函数每次都起作用时 getDerivedStateFromProps
也起作用。
我只希望我的 getDerivedStateFromProps
功能能够像我的旧 UNSAFE_componentWillReceiveProps
功能一样工作。
我该怎么做? 谢谢
您所描述的 problem 可以通过使您的 Component
完全受控或完全不受控但使用钥匙来解决。
第一种方法可能如下所示:
// --- parent component: Parent.tsx
import { Child } from "./Child";
export class Parent extends React.Component<{}, { counter: number }> {
state = { counter: 0 };
render() {
return (
<div>
<div>
<button onClick={() => this.setState(({ counter }) => ({ counter: counter + 1 }))}>increase counter</button>
</div>
<Child
parentCounter={this.state.counter}
setParentCounter={(n) => this.setState({ counter: n })}
/>
</div>
);
}
}
// --- child component : Child.tsx
type Props = { parentCounter: number; setParentCounter: (n: number) => void };
export class Child extends React.Component<Props> {
render() {
const { parentCounter, setParentCounter } = this.props;
return (
<>
<div>parent counter: {parentCounter}</div>
<button
onClick={() => {
setParentCounter(parentCounter + 1);
}}
>
increase parent counter
</button>
</>
);
}
}
因此,不存在两种独立的状态:一种在父组件中,另一种在子组件中。唯一的状态存在于父组件中,子组件有 setter 属性,它可以用来改变父组件的状态。
第二种方法(带键的不受控制的组件)使用这样一个事实,即当 key
更改子组件时,它会从头开始重新呈现并失去其内部状态:
// --- Parent.tsx
import { Child } from "./Child";
export class Parent extends React.Component<{}, { counter: number }> {
state = { counter: 0 };
render() {
const { counter } = this.state;
return (
<div>
<div>parent counter: {counter}</div>
<div>
<button
onClick={() =>
this.setState(({ counter }) => ({ counter: counter + 1 }))
}
>
increase parent counter
</button>
</div>
<Child parentCounter={counter} key={`child-key-${counter}`} />
</div>
);
}
}
// --- Child.tsx
type Props = { parentCounter: number };
type State = { childCounter: number };
export class Child extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { childCounter: props.parentCounter };
}
render() {
return (
<>
<div>child counter {this.state.childCounter}</div>
<button
onClick={() => {
this.setState(({ childCounter }) => ({
childCounter: childCounter + 1
}));
}}
>
increase child counter
</button>
</>
);
}
}