如何根据容器的状态更改来更新组件

时间:2018-07-31 12:05:45

标签: reactjs typescript

我有一个名为UserContainer的React容器,该容器呈现了一个名为UserComponent的组件。

代码大致如下所示(我已删除了不必要的位):

 // **** CONTAINER **** //
    class UserContainer extends React.Component<ContainerProps, ContainerState> {
    state = { firstName: "placeholder" };

    async componentDidMount() {
        const response = await this.props.callUserApi();

        if (response.ok) {
            const content: ContainerState = await response.json();
            this.setState({ firstName: content.firstName });
        }
    }

    private isChanged(componentState: ComponentState) {
        return this.state.firstName === componentState.firstName;
    }

    async save(newValues: ComponentState) {
        if (!this.isChanged(newValues)) {
            console.log("No changes detected.");
            return;
        }

        const response = await this.props.changeFirstName(newValues.firstName);

        if (response.ok) {
            const content: ContainerState = await response.json();
            this.setState({ firstName: content.firstName });
        }
    }

    render() {
        return <UserComponent firstName={this.state.firstName} onSave={(newValues: ComponentState) => this.save(newValues)} />;
    }
}

export default UserContainer;

// **** COMPONENT **** //

class UserComponent extends React.PureComponent<ComponentProps, ComponentState> {
    constructor(props: ComponentProps) {
        super(props);

        this.state = {  firstName: props.firstName }
    }

    render() {
        return (
            <div>
                <input type="text" value={this.state.firstName} onChange={evt => this.setState({ firstName: evt.target.value})} />
                <button type="button" onClick={() => this.props.onSave(this.state)}>Save</button>
            </div>
        );
    }
}

export default UserComponent;

问题是组件中的this.state.firstName始终是“占位符”。即使容器从API获取其值之后,组件的state也不会更改(但是props也会更改)。将console.log添加到各个方法中时,各个步骤的流程如下:

  1. 容器render()
  2. 组件构造器()
  3. 组件render()
  4. 容器didMount()
  5. 容器render()
  6. 组件render()

如您所见,在容器从后端API接收其数据之前,只调用一次组件构造函数。有没有一种方法可以将更新后的容器状态传递到组件中以显示实际数据?

3 个答案:

答案 0 :(得分:1)

确实有一些FEW情况需要通过道具更新状态,我建议您阅读Facebook上“首选解决方案”下的完整博客文章:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

答案 1 :(得分:0)

您已经将更新的数据传递给组件。唯一的错误是,您只分配了一次。因此,每当您获得更新的值时,它都不会反映出来,因为您不会只分配一次。

两种解决方法。

  1. 如果未进行任何操作。将this.state.firstName更改为this.props.firstName

            <input type="text" value={this.props.firstName} onChange={evt => this.setState({ firstName: evt.target.value})} />
    
  2. 如果要进行某些操作,则将使用componentWillReceiveProps方法进行操作,然后设置您的firstName状态。每当您要更新状态时,都会触发此方法。 示例-

    componentWillReceiveProps(nextProps) {
        if(this.props.firstName!==nextProps.firstName) {
            //do your validation
        }
     }
    

编辑

正如dubes正确指出的那样,componentWillReceiveProps方法已被弃用。因此,您将不得不使用static getDerivedStateFromProps并必须从该方法返回新的结果状态。

希望这会有所帮助:)

答案 2 :(得分:0)

class UserComponent extends React.PureComponent<ComponentProps, ComponentState> {
    constructor(props: ComponentProps) {
        super(props); 
        this.state = {  firstName: props.firstName }
    }

    componentWillReceiveProps(nextProps: ComponentProps){
        if(nextProps.firstName != this.props.firstName){
            this.state = {  firstName: nextProps.firstName }
        }
    }

    render() {
        return (
            <div>
                <input type="text" value={this.state.firstName} onChange={evt => this.setState({ firstName: evt.target.value})} />
                <button type="button" onClick={() => this.props.onSave(this.state)}>Save</button>
            </div>
        );
    }

}

对于最新的React版本,请使用 getDerivedStateFromProps