React 初始化并与后台同步状态。

问题描述 投票:1回答:2

我想知道什么是初始化状态并保持与服务器同步的最佳方式模式。在过去的几天里,我阅读并尝试了很多,但没有发现任何解决我问题的方法。

这个例子真的很简单。有一个状态--为了简单起见,在这个例子中它是一个数字,尽管在现实生活中它应该是一个对象--我需要从服务器上检索。一旦检索到,我希望它能与服务器同步。getValueFromServer是一个mock,在setTimeout中随机等待一段时间后返回一个随机值。

所以,为了初始化我的状态,我在一个空数组上使用一个useEffect作为依赖,为了保持同步,我使用一个带有状态的useEffect作为依赖。

问题是它试图保存一个未定义的值。日志如下。

1 -> 第一次初始化。

2 -> API调用保存在服务器中的值:未定义。

3 -> API调用保存在服务器中的数值:6.026930847574949。

我得到了什么。

1:按预期安装运行。

2:这个我没有想到。我猜它是因为 "useState "而被触发的。

3:一旦我们得到服务器的响应就会运行。有点明显,但是很麻烦,因为我到底为什么要保存这个。

最好的方法是什么?在useEffect中使用类似 "isInitialized "的标志与依赖关系,感觉有点黑,不专业。

下面的代码,你也可以在这里找到工作。https:/codesandbox.iosoptimistic-rgb-uce9f

import React, { useState, useEffect } from "react";
import { getValueFromServer } from "./api";

export default function App() {
  const [value, setValue] = useState();

  useEffect(() => {
    async function initialize() {
      console.log("Initializing for first time");
      let serverValue = await getValueFromServer();
      setValue(serverValue);
    }
    initialize();
  }, []);

  useEffect(() => {
    console.log("API call to save in server value: ", value);
  }, [value]);

  const handleClick = () => {
    setValue(value + 1);
  };

  return (
    <div className="App">
      <h1>Value: {value}</h1>
      <button onClick={handleClick}>Add 1 to value</button>
    </div>
  );
}
reactjs react-hooks data-synchronization
2个回答
1
投票

这里最好的方法是什么?在useEffect中使用类似 "isInitialized "的标志与依赖,感觉有点黑,不专业。

你可以使用一个标志,或者用默认值初始化对象在 useState

const { Fragment, useState, useEffect } = React;

const getValueFromServer = () => new Promise((resolve, reject) => setTimeout(() => resolve(Math.random())), 1000)

const App = () => {
  const [value, setValue] = useState(null);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
    let isUnmounted = false;
  
    getValueFromServer().then(serverValue => {
      console.log("Initializing for first time");
      if(isUnmounted) {
        return;
      }
      setValue(serverValue);
      setLoading(false);
    })
    
    return () => {
      isUnmounted = true;
    }
  }, []);

  useEffect(() => {
    if(!value) {
      return () => {}
    }
  
    console.log("API call to save in server value: ", value);
    setTimeout(() => setLoading(false), 50);
  }, [value]);

  const handleClick = () => {
    setLoading(true);
    setValue(value + 1);
  };

  return <div className="App">
    {isLoading ? <Fragment>
      <span>Loading...</span>
    </Fragment> : <Fragment>
      <h1>Value: {value}</h1>
      <button onClick={handleClick}>Add 1 to value</button>
    </Fragment>}
  </div>
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.10.1/polyfill.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>

1
投票

您的应用程序在忙碌的同时还在做其他事情 await在你的第一场比赛中,你会发生一些事情。useEffect 钩子函数。 在这里,"其他东西 "是 "执行你的第二个 useEffect 钩子功能"。 serverValue钩子函数",因此 value,此时还没有定义,所以你的 console.log 印花 undefined一旦你的 await 诺言解析为一个值和 setValue 召之即来,挥之即去 useEffect 钩子函数的依赖关系发生变化,导致你的函数第二次运行(并打印出你期望的值)。

如果你必须有两个 useEffect 钩,然后就在第二种情况下保释出来。value 未定义。

  useEffect(() => {
    if (value === undefined) {
      return;
    }

    console.log('value is:', value);
  }, [ value ]);
© www.soinside.com 2019 - 2024. All rights reserved.