Javascript 反应表单 onChange->setState 落后一步

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28773839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:22:58  来源:igfitidea点击:

React form onChange->setState one step behind

javascriptreactjs

提问by Keith Yong

I encountered this problem building a webapp and I replicated it in this jsfiddle. Essentially, I would like an input to call this.setState({message: input_val})every time I type something into it, then pass it into the parent App class which then re-renders the message onto the Message class. However the output seems to always be one step behind what I actually type. The jsfiddle demo should be self explanatory. I am wondering if I did anything wrong to prompt this.

我在构建 webapp 时遇到了这个问题,我在这个jsfiddle 中复制了它。本质上,我希望this.setState({message: input_val})每次在输入内容时调用一个输入,然后将其传递到父 App 类,然后将消息重新呈现到 Message 类上。然而,输出似乎总是比我实际输入的内容落后一步。jsfiddle 演示应该是不言自明的。我想知道我是否做错了什么来提示这个。

html

html

<script src="http://facebook.github.io/react/js/jsfiddle-integration.js"></script>
<div id='app'></div>

js

js

var App = React.createClass({
    getInitialState: function() {
        return {message: ''}
    },
    appHandleSubmit: function(state) {
        this.setState({message: state.message});
        console.log(this.state.message);
    },
    render: function() {
        return (
            <div className='myApp'>
            <MyForm onChange={this.appHandleSubmit}/>
            <Message message={this.state.message}/>
            </div>
        );
    }
});

var MyForm = React.createClass({
    handleSubmit: function() {
        this.props.onChange(this.state);
    },
    handleChange: function(e) {
        console.log(e.target.value);
        this.setState({message: e.target.value});
        this.handleSubmit();
    },
    render: function() {
        return (
            <form className="reactForm" onChange={this.handleChange}>
            <input type='text' />
            </form>
        );
    }
});

var Message = React.createClass({
    render: function() {
        return (
            <div className="message">
                <p>{this.props.message}</p>
            </div>
        )
    }
});

React.render(
    <App />,
    document.getElementById('app')
);

回答by WiredPrairie

A call to setStateisn't synchronous. It creates a "pending state transition." (See herefor more details). You should explicitly pass the new inputvalue as part of the event being raised (like to handleSubmitin your example).

调用setState不是同步的。它创建了一个“待定状态转换”。(有关更多详细信息,请参见此处)。您应该将新input值作为引发事件的一部分显式传递(就像handleSubmit在您的示例中一样)。

See thisexample.

请参阅示例。

handleSubmit: function(txt) {
    this.props.onChange(txt);
},
handleChange: function(e) {
    var value = e.target.value;
    this.setState({message: value});
    this.handleSubmit(value);
},

回答by RC-Chandan

There is a much simpler way to do this, setState(updater, callback)is an async function and it takes the callback as second argument,

有一个更简单的方法来做到这一点,setState(updater, callback)是一个异步函数,它将回调作为第二个参数,

Simply pass the handleSubmitas a callback to setStatemethod, this way after setState is complete only handleSubmitwill get executed.

只需将handleSubmit作为回调传递给setState方法,这样在 setState 完成后,只有handleSubmit会被执行。

For eg.

例如。

handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit);
}

Try to change the handleChange() method like above and it will work.

尝试像上面一样更改 handleChange() 方法,它会起作用。

for syntax of using setStatecheck this link

有关使用setState检查此链接的语法

回答by Taylor A. Leach

I was pulling my hair out for like an hour because of this so I decided to share... If your callback is still one step behind and seemingly not working, ensure you don't CALLthe function with parenthesis... Just pass it in. Rookie mistake.

由于这个原因,我拉了一个小时的头发,所以我决定分享......如果你的回调仍然落后一步并且似乎不起作用,请确保你不要用括号调用该函数......只需传递它in.菜鸟错误。

RIGHT:

对:

handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit);
}

VS

VS

WRONG:

错误的:

handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit());
}

回答by Brigand

There's no reason for MyForm to be using state here. Also putting the onChange on the form instead of the input you're interested in is odd. Controlled components should be preferred because their behavior is more obvious, and any time App's message state changes (even if you e.g. allow Message to change it later), it'll be correct everywhere.

MyForm 没有理由在这里使用状态。将 onChange 放在表单上而不是您感兴趣的输入上也很奇怪。受控组件应该是首选,因为它们的行为更明显,并且任何时候 App 的消息状态发生变化(即使您例如允许 Message 稍后更改它),它在任何地方都是正确的。

This also makes your code a bit shorter, and considerably simpler.

这也使您的代码更短,并且相当简单。

var App = React.createClass({
    getInitialState: function() {
        return {message: ''}
    },
    appHandleSubmit: function(message) {
        this.setState({message: message});
    },
    render: function() {
        return (
            <div className='myApp'>
                <MyForm onChange={this.appHandleSubmit} 
                        message={this.state.message} />
                <Message message={this.state.message}/>
            </div>
        );
    }
});

var MyForm = React.createClass({
    handleInputChange: function(e){
        this.props.onChange(e.target.value);
    },
    // now always in sync with the parent's state
    render: function() {
        return (
            <form className="reactForm">
                <input type='text' onChange={this.handleInputChange}
                       value={this.props.message} />
            </form>
        );
    }
});

jsbin

jsbin

回答by ishab acharya

Knowing the problem is with not having asyncronous behaviourof setState I solved my issue with async await

知道问题在于没有setState 的异步行为,我用async await解决了我的问题

onChangeEmail=async x =>{
await this.setState({email:x})
}

回答by Sodium United

with setState hook

带有 setState 钩子

useEffect(() => {
    your code...
}, [yourState]);

回答by Ruslan Prokopenko

I found it very cumbersome for me to define 3 handler functions just to get some value to a component's state, so I decided not to use state at all. I just defined an additional property to the component that stored desired value.

我发现定义 3 个处理函数只是为了获取组件状态的一些值对我来说非常麻烦,所以我决定根本不使用状态。我刚刚为存储所需值的组件定义了一个附加属性。

So I ended up with a code that looked something like this:

所以我最终得到了一个看起来像这样的代码:

//...
},
text: '',
handleChange: function(event) {
  this.text = event.target.value;
  this.forceUpdate();
},
render: function() {
    return <div>
      <InputComponent onChange={this.handleChange}/>
      <DisplayComponent textToDisplay={this.text}/>
      </div>
}
//...