在父状态更改时更新子道具

时间:2019-07-12 18:31:26

标签: javascript reactjs

我有一个状态为task的父组件,以及一个处理更改其名称的输入的子组件。输入使用自己的name状态作为输入值。在submitblur之后,将调用父函数来更新父task.name的状态。在componentDidUpdate()上的父级中,是通过websocket发送到服务器的新状态,服务器将更改发送到另一个客户端。

我的组件保留值,因为它处于状态,但是在另一个客户端(刚刚从服务器接收到新值),它保持不变,因为仅在componentDidMount()中设置了输入值。 如何强制这些子组件处于新状态?

父母

componentDidMount() {
    //Recieve changed data from server. This updates the state of all tasks, but doesn't invoke change of Child component because value has been set only in componentDidMount()
    ioClient.on("onDataChanged", (data) => {
        this.setState({tasks: data.tasks});
    });
}

componentDidUpdate() {
    //Sends data to server and invokes change in another clients
    ioClient.emit('onDataChanged',this.state);
}

onTaskUpdate(task) {
    const updatedTasks = this.state.tasks;
    updatedTasks[task.id] = task;
    const newState = {...this.state, tasks: updatedTasks};
    this.setState(newState);
}

render() {
    return (
        {/* ... some code and for cycle of this.state.tasks */}
            <Task key={task.id} 
                  task={task}
                  onTaskUpdate={this.onTaskUpdate}
            />
        {/* ... */}
    );
}

孩子(任务)

constructor(props) {
    super(props);
    this.state = {name: ''};

    this.handleInputChange = this.handleInputChange.bind(this);
    this.nameFormSubmit = this.nameFormSubmit.bind(this);
}

componentDidMount() {
    // component is already mounted so parents change doesn't invoke this again
    this.setState({name: this.props.task.name});
}

handleInputChange(e) {
    this.setState({[e.target.name]: e.target.value});
}

nameFormSubmit(e) {
    e.preventDefault();
    let updatedTask = {...this.props.task, name: this.state.name};
    this.props.onUpdate(updatedTask);
}

render() {
    return (
        <form onSubmit={(e) => this.nameFormSubmit(e)}>
            <input type="text"
                   name="name"
                   value={this.state.name}
                   onChange={this.handleInputChange}
             />
        </form>
    );
}

我正在使用组件自己的状态,因为我不想将每个按下的键发送给服务器,而只是发送给输入的最终状态。 预期结果:仅在提交时发送/发送更改的输入名称,而不是每次更改

1 个答案:

答案 0 :(得分:0)

我当前的解决方案有效,但是我不满意,因为我认为解决方法不正确。

我使用了getDerivedStateFromProps和新状态focused来指示是否必须替换状态。切换focused状态onFocusonBlur

以下更新的子组件:

孩子(任务)

constructor(props) {
    super(props);
    this.state = {
        name: '',
        focused: false
    };
    this.toggleFocusedState = this.toggleFocusedState.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.nameFormSubmit = this.nameFormSubmit.bind(this);
}

static getDerivedStateFromProps(props, state) {
    return !state.focused ? {name: props.task.name} : null;
}

toggleFocusedState(state) {
    this.setState({focused:state});
}

componentDidMount() {
    this.setState({name: this.props.task.name});
}

handleInputChange(e) {
    this.setState({[e.target.name]: e.target.value});
}

nameFormSubmit(e) {
    e.preventDefault();
    let updatedTask = {...this.props.task, name: this.state.name};
    this.props.onUpdate(updatedTask);
}

render() {
    return (
        <form onSubmit={(e) => this.nameFormSubmit(e)}>
            <input type="text"
                   name="name"
                   value={this.state.name}
                   onChange={this.handleInputChange}
                   onFocus={()=>this.toggleFocusedState(true)}
                   onBlur={()=>this.toggleFocusedState(false)}
             />
        </form>
    );
}