Javascript 改变后的反应形式->;落后一步

Javascript 改变后的反应形式->;落后一步,javascript,reactjs,Javascript,Reactjs,我在构建一个webapp时遇到了这个问题,我在这里复制了它。本质上,每次我在其中键入内容时,我都希望有一个输入调用this.setState({message:input_val}),然后将其传递到父应用程序类,然后再将消息重新呈现到message类上。然而,输出似乎总是比我实际键入的内容落后一步。jsfiddle演示应该是不言自明的。我想知道我是否做了什么错事来提示这一点 html js var-App=React.createClass({ getInitialState:函数(){ 返

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

html


js

var-App=React.createClass({
getInitialState:函数(){
返回{消息:“”
},
appHandleSubmit:函数(状态){
this.setState({message:state.message});
console.log(this.state.message);
},
render:function(){
返回(
);
}
});
var MyForm=React.createClass({
handleSubmit:function(){
this.props.onChange(this.state);
},
handleChange:函数(e){
console.log(如target.value);
this.setState({message:e.target.value});
this.handleSubmit();
},
render:function(){
返回(
);
}
});
var Message=React.createClass({
render:function(){
返回(
{this.props.message}

) } }); 反应( , document.getElementById('app') );
setState
的调用不同步。它创建一个“挂起状态转换”。(有关更多详细信息,请参阅)。您应该显式地传递新的
input
值,作为所引发事件的一部分(如示例中的
handleSubmit

参见示例


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

这也使您的代码变得更短,更简单

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>
        );
    }
});
var-App=React.createClass({
getInitialState:函数(){
返回{消息:“”
},
appHandleSubmit:函数(消息){
this.setState({message:message});
},
render:function(){
返回(
);
}
});
var MyForm=React.createClass({
handleInputChange:函数(e){
this.props.onChange(即target.value);
},
//现在始终与父级的状态同步
render:function(){
返回(
);
}
});

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

所以我最终得到了一个类似这样的代码:

//...
},
text: '',
handleChange: function(event) {
  this.text = event.target.value;
  this.forceUpdate();
},
render: function() {
    return <div>
      <InputComponent onChange={this.handleChange}/>
      <DisplayComponent textToDisplay={this.text}/>
      </div>
}
//...
/。。。
},
文本:“”,
handleChange:函数(事件){
this.text=event.target.value;
这个.forceUpdate();
},
render:function(){
返回
}
//...

有一种更简单的方法可以做到这一点,
setState(更新程序,回调)
是一个异步函数,它将回调作为第二个参数

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

例如

handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit);
}
尝试像上面那样更改handleChange()方法,它就会工作


关于使用setState的语法,请检查这个

因为这个原因,我把头发拔了大约一个小时,所以我决定与大家分享。。。如果您的回调仍然落后一步并且似乎不起作用,请确保您不使用括号调用函数。。。把它传过来。新手犯的错误

对:

VS

错:


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

onChangeEmail=async x =>{
await this.setState({email:x})
}
带固定钩

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

您可以将基于类的组件重构为其他人提到的功能组件。缺点是,这可能相当耗时,具体取决于需要重构的代码行数,并且很容易出错

我将使用您的
changeHandler
示例来展示如何在功能组件中实现它

const INITIAL_DATA = {
  message: ""
}
    
const [form, setForm] = useState({...INITIAL_DATA})

const changeHandler = (e) = setForm({
  ...form,
  [e.target.name]: e.target.value
})

<InputField name={message} value={form.message} onChange={changeHandler}>
*注意我们如何在
useffect(()=>{})
hook之后添加依赖项数组

额外信息:

  • 如果依赖项数组为空,则它将仅在组件装载和第一次渲染时运行
  • 如果没有数组,它将在每次页面呈现时运行
  • 如果数组中有状态名称,则每次完成该状态设置时,该名称都将运行

感谢您的重构,我研究了您的代码并从中吸取了一些优点。似乎使用this.props对于纯视图是个好主意,而使用this.state对于控制器是个好主意。大多数情况下,是的。有时会出现类似下拉列表的情况,其中打开/关闭状态可以保持为组件的私有状态(为什么您会关心下拉列表是否在父级中打开?)。此外,有时UI组件需要跟踪光标位置之类的内容,并在渲染中使用它,因此最终会出现在它们的本地状态。仅供参考--此代码无法正常工作
onChange
不会像您在那里所做的那样将输入框的实际文本作为值传输(实际上传递了一个
SyntheticEvent
)。我也不希望容器知道子组件的具体呈现方式,因此它不应该使用
e.target.value
从输入框中提取值。这就是为什么哈维
handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit);
}
handleChange: function(e) {
    console.log(e.target.value);
    this.setState({message: e.target.value}, this.handleSubmit());
}
onChangeEmail=async x =>{
await this.setState({email:x})
}
useEffect(() => {
    your code...
}, [yourState]);
const INITIAL_DATA = {
  message: ""
}
    
const [form, setForm] = useState({...INITIAL_DATA})

const changeHandler = (e) = setForm({
  ...form,
  [e.target.name]: e.target.value
})

<InputField name={message} value={form.message} onChange={changeHandler}>
useEffect(() => {
  doSomeValidationHere()
  orSendOffTheForm()
}, [form])