简体   繁体   English

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

[英]Updating child props on parent state change

I've parent component with state which contains task and child which handles input that changes it's name. 我的父组件的状态包含task和子组件,该子组件处理更改其名称的输入。 Input uses his own name state for inputs value. 输入使用自己的name状态作为输入值。 After submit or blur parents function is invoked to update state of parents task.name . submitblur后, submit调用父函数来更新父task.name状态。 In parent on componentDidUpdate() is new state sent to the server via websocket and server sends changes to another clients. componentDidUpdate()父项中,是通过websocket发送到服务器的新状态,服务器将更改发送到另一个客户端。

My component keep value because it is in it's state but in another clients (which has just recieved new value from server) it is unchanged because value of input has been set only in componentDidMount() . 我的组件保留值,因为它处于状态,但是在另一个客户端(刚刚从服务器接收到新值)中,它保持不变,因为仅在componentDidMount()设置了输入值。 How do I force new state to these child components? 如何对这些子组件强制采用新状态?

Parent 父级

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}
            />
        {/* ... */}
    );
}

Child (Task) 儿童 (任务)

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>
    );
}

I'm using components own state because I don't want to send to server each pressed key but just final state of input. 我使用组件自己的状态,因为我不想将每个已按下的键发送给服务器,而只是发送给输入的最终状态。 Expected result: Emit/send changed inputs name only on submit, not with every change 预期结果:仅在提交时发送/发送更改的输入名称,而不是每次更改

My current solution which works but I am not happy with it because I don't think it's properly resolved. 我当前的解决方案有效,但是我不满意,因为我认为解决方法不正确。

I've used getDerivedStateFromProps and new state focused to indicate if state has to be replaced. 我用getDerivedStateFromProps和新的国家focused来指示状态,必须更换。 Toggling the focused state onFocus and onBlur . 切换focused状态onFocusonBlur

Updated Child component below: 下面更新了子组件:

Child (Task) 儿童 (任务)

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>
    );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM