reactjs——解决setState异步问题

Posted

技术标签:

【中文标题】reactjs——解决setState异步问题【英文标题】:reactjs -- Solving setState async problem 【发布时间】:2019-02-13 00:00:59 【问题描述】:

我读过这篇文章:React setState not Updating Immediately

并意识到 setState 是异步的,可能需要第二个参数作为处理新状态的函数。

现在我有一个复选框

class CheckBox extends Component 
    constructor() 
        super();
        this.state = 
            isChecked: false,
            checkedList: []
        ;
        this.handleChecked = this.handleChecked.bind(this);
    

    handleChecked () 
        this.setState(isChecked: !this.state.isChecked, this.props.handler(this.props.txt));
    

    render () 
        return (
            <div>
                <input type="checkbox" onChange=this.handleChecked />
                `   $this.props.txt`
            </div>
            )
    

并且正在被另一个应用程序使用

class AppList extends Component 
    constructor() 
        super();
        this.state = 
            checked: [],
            apps: []
        ;
        this.handleChecked = this.handleChecked.bind(this);
        this.handleDeleteKey = this.handleDeleteKey.bind(this);
    
    handleChecked(client_id) 
        if (!this.state.checked.includes(client_id)) 
            let new_apps = this.state.apps;
            if (new_apps.includes(client_id)) 
                new_apps = new_apps.filter(m => 
                    return (m !== client_id);
                );
             else 
                new_apps.push(client_id);
            
            console.log('new apps', new_apps);
            this.setState(apps: new_apps);
            // this.setState(checked: [...checked_key, client_id]);
            console.log(this.state);
        
    
    render () 
        const apps = this.props.apps.map((app) =>
            <CheckBox key=app.client_id txt=app.client_id handler=this.handleChecked/>
        );

        return (
            <div>
                <h4>Client Key List:</h4>
                this.props.apps.length > 0 ? <ul>apps</ul> : <p>No Key</p>
            </div> 
        );
    



所以每次复选框状态发生变化时,我都会更新this.state.apps中的AppList

当我 console.log new_apps 时,一切正常,但 console.log(this.state) 显示状态没有立即更新,这是意料之中的。我需要知道的是,当我需要执行进一步操作(例如注册所有这些选定的字符串或其他内容)时,如何确保更新状态

【问题讨论】:

函数 this.setState() 是异步的!但作为第二个参数,您可以调用回调,尝试使用 this.setState( apps: new_apps , _ =&gt; console.log(this.state) 这在反应文档中以及您链接到的问题的答案中有很好的介绍。 @meagar 我不明白为什么我的 console.log 没有输出正确的答案,即使我在复选框中使用了回调函数。这就是为什么这篇文章 【参考方案1】:

实际上不应该有两个状态保持相同的东西。相反,复选框应该是无状态的,状态应该只保留在 AppList 中,然后向下传递:

const CheckBox = ( text, checked, onChange ) => 
        (<span><input type="checkbox" checked=checked onChange=() => onChange(text) />text</span>);
        
class AppList extends React.Component 
  constructor() 
    super();
    this.state =  
      apps: [
        name: "One", checked: false ,
         name: "Two", checked: false 
      ], 
    ;
  
  
  onChange(app) 
    this.setState(
      previous => ( 
         apps: previous.apps.map(( name, checked ) => ( name, checked: checked !== (name === app) )),
      ),
      () => console.log(this.state)
    );
  
  
  render() 
    return <div>
     this.state.apps.map(( name, checked ) => (<CheckBox text=name checked=checked onChange=this.onChange.bind(this) />))
    </div>;
  


ReactDOM.render(<AppList />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

【讨论】:

总的来说,我喜欢您建议的方法,但是 xor 的东西过于聪明(聪明的代码是糟糕的代码)。我建议将其重写为更直接。 @jeff 我不确定嵌套比较是否更好......你对“直截了当”有什么建议? 我得到 input is a void element tag and must neither have children` 也没有使用 dangerouslySetInnerhtml.` 作为错误。 &lt;input&gt; 中的某些东西造成了这个问题? @JonasWilms 我会使用三元组。 checked: name === app ? !checked : checked。也就是说,如果这是我们要切换的应用程序,则切换,否则保持原样。我认为这对未来的读者来说更加清晰和明显,并且不太可能被作者搞砸。【参考方案2】:

setState 可以让你在设置状态后做一个回调函数,这样你就可以得到真实的状态

this.setState(stateYouWant, () => console.log(this.state.stateYouWant))

在你的情况下:

this.setState(apps: new_apps, () => console.log(this.state))

【讨论】:

所以你说的是状态实际上改变成功了。我只是console.log在错误的地方? 我说的是同时执行,所以console.log有旧状态,如果你明白我的意思,它总是落后一个状态,这样做我们只记录状态改变后(回调通常是某个操作完成后调用的函数,在本例中为 setState) 如果它解决了您的问题,请选择正确的答案,以便其他看到此问题的人可以轻松解决 我会尽快完成。 *** 不允许在 5 分钟内选择正确答案【参考方案3】:

其他人对 setState 回调有正确的答案,但我也建议使 CheckBox 无状态并从 MyApp 传递 isChecked 作为道具。这样,您只保留一项是否已检查的记录,而无需在两者之间进行同步。

【讨论】:

只是好奇,现在当复选框更改状态时,我将isChecked 设置为!isChecked。如果我将其作为道具处理,我如何跟踪此状态? 你必须创建一个函数来修改状态并通过道具传递给另一个组件,然后在那里调用它

以上是关于reactjs——解决setState异步问题的主要内容,如果未能解决你的问题,请参考以下文章

setState ReactJS 中的 this.state

ReactJS 中的 this.state 和 this.setstate 有啥区别?

为啥setState是异步的

承诺解决后未触发reactjs render() this.setState 被重新分配

Reactjs-setState 前一个状态是第一个参数,props 作为第二个参数

异步获取数据不重新渲染 ReactJS 数据表(或只是不显示新数据)