【问题标题】:react hook state is not updating on first click第一次点击时反应钩子状态没有更新
【发布时间】:2021-01-30 17:34:06
【问题描述】:

我是新手,我遇到了 useState 钩子的问题。我有一个来自(使用useForm),我想要实现的是当用户单击提交按钮时,它会将表单数据发送到api并从api收集响应然后更新状态并将更新后的状态作为url重定向中的参数发送(道具。历史.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 是我的表单。请让我知道我做错了什么以及我需要添加哪些修复

【问题讨论】:

  • 哪个useState 没有更新?其中有 4 个。什么被点击?我在您的代码 sn-p 中看不到 onClick 处理程序。我的猜测是外壳中的陈旧状态。 sendRequest 是否传递给多个子组件?如果不是,那么我怀疑它需要被记忆。
  • 代码有点复杂。只需一个处理程序 sendRequest 即可简化,无需记忆。要调试您的问题,请尝试在 createProcessApiCall(new_param) 的 .then 处设置断点,看看它是否甚至到达那里。如果到达,请检查 dt 回调是否已执行。可能会放一个临时的 useEffect 来查看 postApiData 是否更新。
  • @DrewReese 我正在更新状态 postApiData。在我尝试 console.log(postApiData) 的 sendRequest 中,我得到了空钩
  • @KevinMoeMyintMyat 数据在第二次单击按钮时得到更新,是的,它正在到达 createProcessApiCall(new_param),我正在从 API 获得响应
  • @KevinMoeMyintMyat 请告诉我如何简化我的代码

标签: reactjs


【解决方案1】:

试试这个:

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

【讨论】:

    【解决方案2】:

    问题

    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. sendRequest 设为异步函数,将await 设为来自postData 在try/catch 中的响应
    2. 如果成功则继续导航,如果 promise 拒绝则在 catch 中设置错误
    3. postData 返回 Promise,而不是传递状态更新函数

    发布数据

    解压响应数据并返回

    const postData = param => {
      const new_param = JSON.stringify(param);
    
      return createProcessApiCall(new_param)
        .then((response) => {
          return response.data.data;
        });
    };
    

    创建进程容器

    删除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 传递回调

    发布数据

    解压响应数据并将其传递给并调用成功回调。将失败回调传递给 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);
    };
    

    创建进程容器

    移除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>
      );
    }
    

    【讨论】:

    • 我已经解决了。非常感谢您的努力,非常感谢。
    【解决方案3】:

    以下更改解决了我的问题,如果我可以改进代码,请告诉我

    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>
    
        )
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多