【问题标题】:How use async return value from useEffect as default value in useState?如何使用 useEffect 的异步返回值作为 useState 中的默认值?
【发布时间】:2018-11-14 10:59:15
【问题描述】:

我创建了一个简单的示例https://codesandbox.io/s/4zq852m7j0

如您所见,我正在从远程源获取一些数据。我想将返回值用作我的文本字段中的值。

const useFetch = () => {
  const [value, setValue] = useState("");

  useEffect(
    async () => {
      const response = await fetch("https://httpbin.org/get?foo=bar");
      const data = await response.json();
      setValue(data.args.foo);
    },
    [value]
  );

  return value;
};

但是,使用 useState 函数中的值不起作用。我认为useState 仅在第一次渲染时使用默认值。首次渲染时,显然没有设置该值,因为它是异步的。文本字段的值应该是 bar,但它是空的。

function App() {
  const remoteName = useFetch();
  // i want to see the remote value inside my textfield
  const [name, setName] = useState(remoteName);

  const onChange = event => {
    setName(event.target.value);
  };

  return (
    <div className="App">
      <p>remote name: {remoteName}</p>
      <p>local name: {name}</p>
      <input onChange={onChange} value={name} />
    </div>
  );
}

从远程获取值后,我希望能够在本地更改它。

有什么想法吗?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    既然useFetch返回了一个异步可用的值,你需要在remoteValue可用时更新localState,这样你就可以写一个效果了

    const remoteName = useFetch();
      // i want to see the remote value inside my textfield
      const [name, setName] = useState(remoteName);
      useEffect(
        () => {
          console.log("inside effect");
          setName(remoteName);
        },
        [remoteName] // run when remoteName changes
      );
    
      const onChange = event => {
        setName(event.target.value);
      };
    

    Working demo

    【讨论】:

      【解决方案2】:

      这与在类组件中异步设置初始状态完全相同:

      state = {};
      
      async componentDidMount() {
        const response = await fetch(...);
        ...
        this.setState(...);
      }
      

      在初始渲染期间异步检索的状态不可用。函数组件应该使用与类组件相同的技术,即有条件地渲染依赖于状态的子组件:

        return name && <div className="App">...</div>;
      

      这样useFetch就没有理由拥有自己的状态,它可以与组件保持共同的状态(example):

      const useFetch = () => {
        const [value, setValue] = useState("");
      
        useEffect(
          async () => {
            const response = await fetch("https://httpbin.org/get?foo=bar");
            const data = await response.json();
            setValue(data.args.foo);
          },
          [] // executed on component mount
        );
      
        return [value, setValue];
      };
      
      function App() {
        const [name, setName] = useFetch();
      
        const onChange = event => {
          setName(event.target.value);
        };
      
        return name && (
          <div className="App">
            <p>local name: {name}</p>
            <input onChange={onChange} value={name} />
          </div>
        );
      }
      

      【讨论】:

      • bar 为空字符串(删除文本字段内的值)时,整个组件都消失了。
      • 如果使用空字符串作为初始状态不能满足您的目的,请不要使用它。您可以使用useState() 并改为使用name != null &amp;&amp; ... 检查。
      【解决方案3】:

      不能将初始状态作为异步函数传递吗?

       const [value, setValue] = useState(async () => fetch("https://httpbin.org/get?foo=bar").json().args.foo);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-16
        • 1970-01-01
        • 2012-08-01
        • 2021-10-08
        • 1970-01-01
        相关资源
        最近更新 更多