如何在更新状态情况下使用 getDerivedStateFromProps?

时间:2021-06-20 22:25:05

标签: javascript reactjs typescript refactoring react-lifecycle

我对代码的重构感到困惑。

我的组件是这样工作的 ==> 我将来自父组件的传入 props 设置为子组件的状态。然后我就可以在组件中进行更新状态操作了。

这是我的 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,状态更新为旧道具。因为每次 getDerivedStateFromProps 都起作用时 onChange 函数也起作用。

我只希望我的 getDerivedStateFromProps 函数能够像我旧的 UNSAFE_componentWillReceiveProps 函数一样工作。

我该怎么做? 谢谢

1 个答案:

答案 0 :(得分:0)

您所描述的 docs found here 可以通过使您的 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 prop 可以用来改变父组件的状态。

第二种方法(带有键的不受控制的组件)使用的事实是,当 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>
      </>
    );
  }
}