第一次单击时反应挂钩状态未更新

时间:2020-10-16 07:50:11

标签: reactjs

我是新来的反应者,我正面临useState挂钩的问题。我有一个来自(使用useForm)的应用程序,我想要实现的是当用户单击Submit按钮时,它将向api发送表单数据并从api收集响应,然后更新状态并将该更新后的状态作为url重定向中的参数发送(道具。 history.push)。 我唯一遇到的问题是useState挂钩在第一次单击时未更新。我发现了类似的问题,但是并不能解决我的问题,或者可以说我不太了解,请帮忙。

import React, {useState, useRef, useCallback, useEffect} from 'react'
import {useForm} from 'react-hook-form'
import CreateProcessComponent from '../../components/ProcessComponents/CreateProcess/CreateProcessComponent.jsx'
import {createProcessApiCall} from '../../services/ProcessService'


function postData (dt, err, param){
     var new_param = JSON.stringify(param)
        const result = createProcessApiCall(new_param)
            .then(response => {
                dt(response.data.data)
                console.log(response.data.data)
          })
          .catch(e => {
            console.log(e)
            err(true)
          })
        }
      
    

export default function CreateProcessContainer(props){

    const {register, handleSubmit, errors} = useForm()
    const [postApiData, setApiData] = useState({})
    const [isError, setIsError] = useState(false);

  
  
    const sendRequest= (data) => {
      let prm = {"ProcessName":data.processName,"ProcessDescription":data.processDescription,"Code":"null", "CreatedBy":"null"}
      postData(setApiData, setIsError, prm)
      props.history.push({pathname:'/test',state:{postApiData}})
    }


  

    return (
          <main>
            {isError && <div>Something went wrong ...</div>}
            { (!isError)  ?
            <CreateProcessComponent 
                register={register} 
                handleSubmit={handleSubmit} 
                errors={errors}
                onSubmit={sendRequest}/>
                :
                null }

            </main>

    )
}
上面的代码中的

CreateProcessComponent是我的表单。请让我知道我做错了什么以及需要添加哪些修复程序

3 个答案:

答案 0 :(得分:0)

尝试一下:

const main = useRef(null);
if(main) {}
<main ref={main}>

PS:没感觉

    // set isMounted to false when we unmount the component
    useEffect(() => {
      return () => {
        isMounted.current = false
      }
    }, [])

您的组件将销毁,isMounted被设置成什么?

答案 1 :(得分:0)

问题

sendRequest正在更新状态,但是您正在尝试获取下一行导航推的更新状态。 React状态更新是异步的,并且更新的postApiData状态值直到至少一个渲染周期之后才可用。 postData还在做一些异步处理,但是它没有返回可以等待的承诺。

所以基本上sendRequest会触发postData调用,然后立即进行导航,因为此功能是完全同步的

const sendRequest= (data) => {
  ...
  postData(setApiData, setIsError, prm) // <-- setApiData updates state
  props.history.push({
    pathname: '/test',
    state: { postApiData } // <-- current state
  });
}

解决方案1 ​​

  1. 在try / catch中使sendRequest为异步函数,并且await来自postData的响应
  2. 如果成功,则继续导航,如果promise拒绝,则在catch中设置错误
  3. postData返回承诺,而不传递状态更新功能

postData

解压缩响应数据并返回

const postData = param => {
  const new_param = JSON.stringify(param);

  return createProcessApiCall(new_param)
    .then((response) => {
      return response.data.data;
    });
};

CreateProcessContainer

删除postApiData状态并等待来自postData的响应。

export default function CreateProcessContainer(props) {
  const { register, handleSubmit, errors } = useForm();
  const [isError, setIsError] = useState(false);

  const sendRequest = async (data) => {
    const prm = {
      ProcessName: data.processName,
      ProcessDescription: data.processDescription,
      Code: "null",
      CreatedBy: "null"
    };

    try {
      const postApiData = await postData(prm);
      history.push({ pathname: "/result", state: { postApiData } });
    } catch {
      setIsError(true);
    }
  };

  return (
    <main>
      {isError ? (
        <div>Something went wrong ...</div>
      ) : (
        <CreateProcessComponent
          register={register}
          handleSubmit={handleSubmit}
          errors={errors}
          onSubmit={sendRequest}
        />
      )}
    </main>
  );
}

解决方案2

  1. 使帖子数据接受成功和失败的回调以处理承诺解决/拒绝
  2. 传递来自sendRequest的回调

postData

解压缩响应数据并将其传递给并调用成功回调。将失败回调传递给catch块。

const postData = (param, success, failure) => {
  const new_param = JSON.stringify(param);

  createProcessApiCall("result data from callbacks")
    .then((response) => {
      success(response.data.data);
    })
    .catch(failure);
};

CreateProcessContainer

删除postApiData状态,并将参数和成功/失败回调传递给postData

export default function CreateProcessContainer(props) {
  const { register, handleSubmit, errors } = useForm();
  const [isError, setIsError] = useState(false);

  const sendRequest = (data) => {
    const prm = {
      ProcessName: data.processName,
      ProcessDescription: data.processDescription,
      Code: "null",
      CreatedBy: "null"
    };
    postData
      prm,
      (postApiData) => {
        history.push({ pathname: "/result", state: { postApiData } });
      },
      () => setIsError(true)
    );
  };

  return (
    <main>
      {isError ? (
        <div>Something went wrong ...</div>
      ) : (
        <CreateProcessComponent
          register={register}
          handleSubmit={handleSubmit}
          errors={errors}
          onSubmit={sendRequest}
        />
      )}
    </main>
  );
}

Edit react-hook-state-is-not-updating-on-first-click

答案 2 :(得分:0)

下面的更改解决了我的问题,让我知道是否可以改进代码

import React, {useState, useRef, useCallback, useEffect} from 'react'
import {useForm} from 'react-hook-form'
import CreateProcessComponent from '../../components/ProcessComponents/CreateProcess/CreateProcessComponent.jsx'
import {createProcessApiCall} from '../../services/ProcessService'



    

export default function CreateProcessContainer(props){

    const {register, handleSubmit, errors} = useForm()
    const [postApiData, setApiData] = useState({})
    const [isError, setIsError] = useState(false);


    function postData (dt, err, param){
      var new_param = JSON.stringify(param)
         createProcessApiCall(new_param)
             .then(response => {
                 dt(response.data.data)
                //  dt(response.data.data)
                 console.log(response.data.data)
           })
           .catch(e => {
             console.log(e)
             err(true)
           })
         }
       

useEffect(()=>{if (Object.keys(postApiData).length > 0)
  props.history.push({pathname:'/test',state:postApiData})},[postApiData])
  
  
  
    const sendRequest= (data) => {
      let prm = {"ProcessName":data.processName,"ProcessDescription":data.processDescription,"Code":"null", "CreatedBy":"null"}
      postData(setApiData, setIsError, prm)
    }


    return (
          <main>
            {isError && <div>Something went wrong ...</div>}
            { (!isError)  ?
            <CreateProcessComponent 
                register={register} 
                handleSubmit={handleSubmit} 
                errors={errors}
                onSubmit={sendRequest}/>
                :
                null }
            </main>

    )
}