在状态更改之前对运行代码进行反应

时间:2020-07-06 16:28:34

标签: javascript reactjs ecmascript-6

我是React和ES6的新手,我有一个像这样的组件:

import React, { useState } from 'react';

const Order = () => {
    let username='Test',password = 'secret';
    const [Data,setData]=useState({title:'',submit:false});
    const [List,setList]=useState({title:'',submit:false});
    const Clicked = ()=>{
        if(username==='Test'){
            setData({title:'Yes',submit:true});
        }
        else{
            setData({title:'No',submit:false});
        }
        if(password==='secret'){
            setList({title:'Yes',submit:true});
        }
        else{
            setList({title:'No',submit:false});
        }
        console.log(Data.submit,List.submit);
        if(Data.submit && List.submit){
            alert('Time to Submit')
        }
    }
    return (
        <div>
            <button onClick={Clicked}>Click</button>
        </div>
    );
}
 
export default Order;

我的问题是,当我单击Button时,Data.submitList.submit在第一次单击时都被认为是False,但是在第二次单击时它们都变为true,并且会警告alert('Time to Submit')。 因为我将数据和列表用于两个不同的按钮,所以不能使用useEffect()。 我不希望用户单击两次。我该如何处理?

5 个答案:

答案 0 :(得分:2)

这主要是因为设置状态是异步的,因此,如果您像同步代码那样调用,它将无法按预期工作。

要解决此问题,您可以执行以下操作:

import React, { useState } from 'react';

const Order = () => {
    let username='Test',password = 'secret';
    const [Data,setData]=useState({title:'',submit:false});
    const [List,setList]=useState({title:'',submit:false});
    const Clicked = ()=>{
        const data = {title: '', submit: false};
        const list = {title: '', submit: false};

        if(username==='Test'){
            data.title = 'Yes';
            data.submit = true;
        }
        else{
            data.title = 'No';
            data.submit = false;
        }
        if(password==='secret'){
            list.title = 'Yes';
            list.submit = true;
        }
        else{
            list.title = 'No';
            list.submit = false;
        }
        console.log(Data.submit,List.submit);
        if(data.submit && list.submit){
            alert('Time to Submit')
        }
        setData(data);
        setList(list);
    }
    return (
        <div>
            <button onClick={Clicked}>Click</button>
        </div>
    );
}
 
export default Order;

答案 1 :(得分:1)

const Order = () => {
  let username = "Test",
    password = "secret";
  const [Data, setData] = useState({ title: "", submit: false });
  const [List, setList] = useState({ title: "", submit: false });
  const Clicked = () => {
    let dataSubmit, listSubmit;
    if (username === "Test") {
      dataSubmit = true;
      setData({ title: "Yes", submit: true });
    } else {
      setData({ title: "No", submit: false });
    }
    if (password === "secret") {
      listSubmit = true;
      setList({ title: "Yes", submit: true });
    } else {
      setList({ title: "No", submit: false });
    }
    if (dataSubmit && listSubmit) {
      alert("Time to Submit");
    }
  };
  return (
    <div>
      <button onClick={Clicked}>Click</button>
    </div>
  );
};

答案 2 :(得分:1)

setState是异步的(React将决定何时应用更改以提高性能),在您登录控制台时,状态尚未更改。如果您不想使用useEffect来检测状态何时更改,可以使用函数中已有的变量

    const Clicked = ()=>{
        if(username==='Test'){
            setData({title:'Yes',submit:true});
        }
        else{
            setData({title:'No',submit:false});
        }
        if(password==='secret'){
            setList({title:'Yes',submit:true});
        }
        else{
            setList({title:'No',submit:false});
        }
        if(username==='Test' && password==='secret'){
            alert('Time to Submit')
        }
    }

答案 3 :(得分:0)

useState回调与我的直觉是异步的,这就是为什么日志记录输出数据的不变版本的原因。 @Nishant的上述解决方案应该可以正常工作。

答案 4 :(得分:0)

这是我想出的解决方案,我添加了一些评论以使其更加清楚,如果您有任何疑问,请随时向我提问。 (请注意,我不是母语人士,由于我的英语不好意思)

import React, { useState, useEffect } from 'react';

    const Order = () => {
        let username='Test',password = 'secret';
        //fist of all, I recomend you to call your useState variables
        //always using lowercase becase if you name it uppercase
        //it means that is a component o a class
        const [data, setData]=useState({title:'',submit:false});
        const [list, setList]=useState({title:'', submit:false});

        //I also recomment to call you functions using camelCase using the first letter with lowercase
        const clicked = ()=>{
          // I created a couple variables to improve readability and help with logic
          const correctUsername = username === 'Test' //this will return true if username equal test, otherwise will return false;
          const correctPassword = password === 'secret'; //same here

          //Here, you can use a ternary, that is the same as is else, but in a short way
          // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
          setData(correctUsername ? {title: 'Yes', submit: true} : {title: 'No', submit: false});
          setList(correctPassword ? {title: 'Yes', submit: true} : {title: 'No', submit: false});
        }

        
    //You can use an useEffect to watch stateChanges
        useEffect(()=>{
          if(data.submit && list.submit){
            console.log({data, list})
            alert('Time to Submit')
            }
          },[data, list]) 

        return (
            <div>
                <button onClick={clicked}>Click</button>
            </div>
        );
    }
    
    export default Order;