Javascript useState钩子有过时的数据

Javascript useState钩子有过时的数据,javascript,reactjs,Javascript,Reactjs,我正在使用useStatehook将下拉列表中的值设置为变量。在我的onDeviceIdChange中的特定实例中,我将setDeviceId设置为value,它是从我正在使用的组件库中的事件发出的值保持我期望的正确值,但是它不会立即更新到设备ID 我已经阅读了与此问题相关的各种帖子,最常见的解决方案似乎是将变量传递给useffect import React, { useState, useEffect } from "react"; import axios from "axios"; i

我正在使用
useState
hook将下拉列表中的值设置为变量。在我的
onDeviceIdChange
中的特定实例中,我将
setDeviceId
设置为
value
,它是从我正在使用的组件库中的事件发出的<代码>值保持我期望的正确值,但是它不会立即更新到
设备ID

我已经阅读了与此问题相关的各种帖子,最常见的解决方案似乎是将变量传递给
useffect

import React, { useState, useEffect } from "react";
import axios from "axios";

import { Dropdown, Form, Input } from "semantic-ui-react";

const Example = props => {
  const [deviceId, setDeviceId] = useState("");
  const [hardware, setHardware] = useState([]);
  const [error, setError] = useState("");
  const [versionNum, setVersionNum] = useState("");
  const [isLoading, setIsLoading] = useState(true);

  async function fetchDeviceIds() {
    const url = "/api/hardware";
    try {
      const response = await fetch(url, {
        method: "GET"
      });

      if (!response.ok) {  
        setError(response.statusText);
      }

      const data = await response.json();
      console.log(data);   
      setHardware(data.hardware);
    } catch (error) {
      console.log("error catch", error);
      console.log("Handle networking errors", error.message);
    }
  }

  const versionUrl = "/api/versionUrl";
  const onDeviceIdChange = async (e, { value }) => {
    console.log("device id value --> ", value);
    setDeviceId(value);
    console.log(deviceId); //this won't update immediately

    if (!deviceId) {
      handleClear();
      return;
    }

      try {
        console.log("calling versionUrl");
        const response = fetch(versionUrl, {
          method: "POST",
          body: JSON.stringify({
            deviceId: deviceId
          }),
          headers: {
            "Content-Type": "application/json"
          }
        });

        if (!response.ok) {
          setError(response.statusText);
        }
        const data = response.json();
        console.log(data);
        setVersionNum(data.version_num);
        setIsLoading(false);
      } catch (error) {
        console.log("error catch", error);
        console.log("Handle networking errors", error.message);
      }
    }
  };

  useEffect(() => {
    fetchDeviceIds();
  }, []);

  const handleClear = () => {
    setDeviceId("");
    setVersionNum("");
    setIsLoading(true);
  };

  return (
    <>
      <Form.Field required>
        <label style={{ display: "block" }}>device Id</label>
        <Dropdown
          id="deviceId"
          value={deviceId}
          onChange={onDeviceIdChange}
          selection
          fluid
          placeholder="Please select an device ID"
          clearable
          options={hardware.map(device => {
            return {
              text: device.id,
              value: device.id,
              key: device.id
            };
          })}
          style={{ marginTop: ".33", marginBottom: "2em" }}
        />
      </Form.Field>
      <Form.Field>
        <label style={{ display: "block", marginTop: "2em" }}>Version Number</label>

        {isLoading ? (
          <Input
            loading
            iconPosition="left"
            fluid
            placeholder="Choose an device ID..."
            value={versionNum}
          />
        ) : (
          <Input value={versionNum} fluid readOnly />
        )}
      </Form.Field>
    </>
  );
};

export default Example;
像这样的

  useEffect(() => {
    fetchDeviceIds();
    console.log("call back for device id selection", deviceId);
  }, [deviceId]);
但这似乎只是为我反复启动
fetchDeviceID
函数,而从未真正调用更改处理程序。我尝试了
useffect
的一些变体,但未能在
deviceId

下面是我的初始实现,没有将
deviceId
放入
useffect

import React, { useState, useEffect } from "react";
import axios from "axios";

import { Dropdown, Form, Input } from "semantic-ui-react";

const Example = props => {
  const [deviceId, setDeviceId] = useState("");
  const [hardware, setHardware] = useState([]);
  const [error, setError] = useState("");
  const [versionNum, setVersionNum] = useState("");
  const [isLoading, setIsLoading] = useState(true);

  async function fetchDeviceIds() {
    const url = "/api/hardware";
    try {
      const response = await fetch(url, {
        method: "GET"
      });

      if (!response.ok) {  
        setError(response.statusText);
      }

      const data = await response.json();
      console.log(data);   
      setHardware(data.hardware);
    } catch (error) {
      console.log("error catch", error);
      console.log("Handle networking errors", error.message);
    }
  }

  const versionUrl = "/api/versionUrl";
  const onDeviceIdChange = async (e, { value }) => {
    console.log("device id value --> ", value);
    setDeviceId(value);
    console.log(deviceId); //this won't update immediately

    if (!deviceId) {
      handleClear();
      return;
    }

      try {
        console.log("calling versionUrl");
        const response = fetch(versionUrl, {
          method: "POST",
          body: JSON.stringify({
            deviceId: deviceId
          }),
          headers: {
            "Content-Type": "application/json"
          }
        });

        if (!response.ok) {
          setError(response.statusText);
        }
        const data = response.json();
        console.log(data);
        setVersionNum(data.version_num);
        setIsLoading(false);
      } catch (error) {
        console.log("error catch", error);
        console.log("Handle networking errors", error.message);
      }
    }
  };

  useEffect(() => {
    fetchDeviceIds();
  }, []);

  const handleClear = () => {
    setDeviceId("");
    setVersionNum("");
    setIsLoading(true);
  };

  return (
    <>
      <Form.Field required>
        <label style={{ display: "block" }}>device Id</label>
        <Dropdown
          id="deviceId"
          value={deviceId}
          onChange={onDeviceIdChange}
          selection
          fluid
          placeholder="Please select an device ID"
          clearable
          options={hardware.map(device => {
            return {
              text: device.id,
              value: device.id,
              key: device.id
            };
          })}
          style={{ marginTop: ".33", marginBottom: "2em" }}
        />
      </Form.Field>
      <Form.Field>
        <label style={{ display: "block", marginTop: "2em" }}>Version Number</label>

        {isLoading ? (
          <Input
            loading
            iconPosition="left"
            fluid
            placeholder="Choose an device ID..."
            value={versionNum}
          />
        ) : (
          <Input value={versionNum} fluid readOnly />
        )}
      </Form.Field>
    </>
  );
};

export default Example;
import React,{useState,useffect}来自“React”;
从“axios”导入axios;
从“语义ui react”导入{下拉列表、表单、输入};
const-Example=props=>{
const[deviceId,setDeviceId]=useState(“”);
const[hardware,setHardware]=useState([]);
const[error,setError]=useState(“”);
const[versionNum,setVersionNum]=useState(“”);
const[isLoading,setIsLoading]=useState(true);
异步函数fetchDeviceID(){
const url=“/api/hardware”;
试一试{
const response=等待获取(url{
方法:“获取”
});
如果(!response.ok){
setError(response.statusText);
}
const data=wait response.json();
控制台日志(数据);
设置硬件(数据硬件);
}捕获(错误){
日志(“错误捕获”,错误);
log(“处理网络错误”,error.message);
}
}
const versionUrl=“/api/versionUrl”;
const ondevicedchange=async(e,{value})=>{
log(“设备id值-->”,值);
setDeviceId(值);
console.log(deviceId);//这不会立即更新
如果(!设备ID){
handleClear();
返回;
}
试一试{
log(“调用versionUrl”);
const response=fetch(versionUrl{
方法:“张贴”,
正文:JSON.stringify({
deviceId:deviceId
}),
标题:{
“内容类型”:“应用程序/json”
}
});
如果(!response.ok){
setError(response.statusText);
}
const data=response.json();
控制台日志(数据);
setVersionNum(data.version\u num);
设置加载(假);
}捕获(错误){
日志(“错误捕获”,错误);
log(“处理网络错误”,error.message);
}
}
};
useffect(()=>{
fetchDeviceID();
}, []);
常量handleClear=()=>{
setDeviceId(“”);
setVersionNum(“”);
设置加载(真);
};
返回(
设备Id
{
返回{
text:device.id,
值:device.id,
关键字:device.id
};
})}
风格={{marginTop:.33],marginBottom:“2em”}
/>
版本号
{孤岛加载(
) : (
)}
);
};
导出默认示例;
setState()不会立即改变this.state,但会创建挂起的状态转换。调用此方法后访问this.state可能会返回现有值。无法保证对setState调用的同步操作,并且可能会对调用进行批处理以提高性能

React不会更新状态,当您使用console.log时,您将获得以前的值

在您的情况下,您可以将
用于所有同步操作,因为它是您正在设置的新值,或者您可以将setState下方的所有代码移动到
useffect

import React, { useState, useEffect } from "react";
import axios from "axios";

import { Dropdown, Form, Input } from "semantic-ui-react";

const Example = props => {
  const [deviceId, setDeviceId] = useState("");
  const [hardware, setHardware] = useState([]);
  const [error, setError] = useState("");
  const [versionNum, setVersionNum] = useState("");
  const [isLoading, setIsLoading] = useState(true);

  async function fetchDeviceIds() {
    const url = "/api/hardware";
    try {
      const response = await fetch(url, {
        method: "GET"
      });

      if (!response.ok) {  
        setError(response.statusText);
      }

      const data = await response.json();
      console.log(data);   
      setHardware(data.hardware);
    } catch (error) {
      console.log("error catch", error);
      console.log("Handle networking errors", error.message);
    }
  }

  const versionUrl = "/api/versionUrl";
  const onDeviceIdChange = async (e, { value }) => {
    console.log("device id value --> ", value);
    setDeviceId(value);
    console.log(deviceId); //this won't update immediately

    if (!deviceId) {
      handleClear();
      return;
    }

      try {
        console.log("calling versionUrl");
        const response = fetch(versionUrl, {
          method: "POST",
          body: JSON.stringify({
            deviceId: deviceId
          }),
          headers: {
            "Content-Type": "application/json"
          }
        });

        if (!response.ok) {
          setError(response.statusText);
        }
        const data = response.json();
        console.log(data);
        setVersionNum(data.version_num);
        setIsLoading(false);
      } catch (error) {
        console.log("error catch", error);
        console.log("Handle networking errors", error.message);
      }
    }
  };

  useEffect(() => {
    fetchDeviceIds();
  }, []);

  const handleClear = () => {
    setDeviceId("");
    setVersionNum("");
    setIsLoading(true);
  };

  return (
    <>
      <Form.Field required>
        <label style={{ display: "block" }}>device Id</label>
        <Dropdown
          id="deviceId"
          value={deviceId}
          onChange={onDeviceIdChange}
          selection
          fluid
          placeholder="Please select an device ID"
          clearable
          options={hardware.map(device => {
            return {
              text: device.id,
              value: device.id,
              key: device.id
            };
          })}
          style={{ marginTop: ".33", marginBottom: "2em" }}
        />
      </Form.Field>
      <Form.Field>
        <label style={{ display: "block", marginTop: "2em" }}>Version Number</label>

        {isLoading ? (
          <Input
            loading
            iconPosition="left"
            fluid
            placeholder="Choose an device ID..."
            value={versionNum}
          />
        ) : (
          <Input value={versionNum} fluid readOnly />
        )}
      </Form.Field>
    </>
  );
};

export default Example;
更新

从下面的代码和

第二个参数将是形状
{data:value}
因此,您的参数
将始终是未定义的

const onDeviceIdChange = async (e, {value}) => {
    console.log("device id value --> ", value);
    console.log("device value from event --> ", e.target.value);
    setDeviceId(value);
  };

useEffect(() => {
    if (!deviceId) {
      handleClear();
      return;
    }
      try {
        console.log("calling versionUrl");
        const response = fetch(versionUrl, {
          method: "POST",
          body: JSON.stringify({
            deviceId: deviceId
          }),
          headers: {
            "Content-Type": "application/json"
          }
        });

        if (!response.ok) {
          setError(response.statusText);
        }
        const data = response.json();
        console.log(data);
        setVersionNum(data.version_num);
        setIsLoading(false);
      } catch (error) {
        console.log("error catch", error);
        console.log("Handle networking errors", error.message);
      }
    }
},[deviceId])

onDeviceIdChange
应如下所示:

const onDeviceIdChange = async (e, { value }) => {
    // code for validating value etc
    setDeviceId(value);
}
其余的代码应该进入依赖于
deviceId
useffect
钩子:

useEffect(fetchId, [deviceId]);

所以在
setDeviceId
之后,我有一个
if
块,它检查
value
是否存在,如果不存在,它调用的是
handleClear
,似乎每次都会触发。因此,我的异步操作永远不会到达try块。您没有向该值传递任何值!它发送
数据
它不发送
数据
,当登录到更改句柄时,这是未定义的。请考虑不要对其进行分解并打印值,这样依赖于
deviceId
的try/catch块的其余部分应该进入
useffect
?@DJ2您可以将获取id的代码包装到一个名为
fetchId
的函数中,并将其放入
useffect