如何使用异步数据库调用通过 useState() 和 useEffect() 设置变量?

时间:2021-03-06 18:31:10

标签: javascript reactjs promise react-hooks

我正在尝试使用简单的 GET 数据库调用来设置变量。数据库调用正确返回数据,但每次重新渲染后变量保持未定义。代码如下... getMyThing() 函数中的 useState() 函数工作正常并返回我想要的数据。

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
  const { id } = useParams();
  const [myThing, setMyThing] = useState(getMyThing(id));

  useEffect(() => {
    setMyThing(myThing)
  }, [myThing]);
}

我在这里的想法是使用 useState() 来设置 myThing 变量的初始状态以及从我的数据库返回的数据。我认为它不会立即工作,因为数据库调用是异步的,所以我想我可以在数据库调用的响应完成后使用 useEffect() 更新 myThing 变量,因为这会触发 {{1 }} 函数,因为我将 useEffect() 变量包含为依赖项。

我在这里错过了什么?谢谢!

编辑:感谢大家的回答,但我仍然无法通过在 myThing 中异步调用 getMyThing 函数来使其工作。我的数据库调用函数有问题吗?我猜它没有设置为回报承诺?看起来像这样:

useEffect()

3 个答案:

答案 0 :(得分:1)

如果 getMyThing 返回一个 Promise,则 myThing 将在第一次渲染时设置为该 Promise,然后 myThing 将继续引用该 Promise。 setMyThing(myThing) 只是再次将状态设置为 Promise - 这是多余的。

改为调用效果钩子内部的异步方法:

const [myThing, setMyThing] = useState();
useEffect(() => {
    getMyThing(id)
        .then(setMyThing);
}, []);

此处,myThing 将从 undefined 开始,然后在异步调用解决后立即设置为该结果。

答案 1 :(得分:1)

不能用异步获取的值设置初始状态,因为你不能及时得到值。

myThing 不能同时返回您希望异步的值。也许它会返回一个可解析为您想要的内容的承诺。

使用一些默认数据设置初始值。这可能是空数据(稍后当您从组件返回一些 JSX 时,您可以通过例如返回 Loading 消息来特殊情况 myThing === null)。

const [myThing, setMyThing] = useState(null);

useEffect 中触发异步调用,就像您现在所做的一样,但是:

  • 让它在依赖的数据发生变化时重新运行,而不是在它设置的数据发生变化时重新运行。
  • 处理您的代码使用的任何异步机制。在这个例子中,我假设它返回一个 promise。

因此:

useEffect(async () => {
    const myNewThing = await getMyThing(id);
    setMyThing(myNewThing)
}, [id]);

答案 2 :(得分:1)

应该useEffect 挂钩和事件处理程序中执行所有副作用(获取数据、订阅等)。不要在 useState 中执行异步逻辑,因为您只是将承诺本身分配给变量而不是它的结果。无论如何,这是一种不好的做法,而且不会奏效。您应该:

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
    const { id } = useParams();

    const [myThing, setMyThing] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            const result = await getMyThing(id);

            setMyThing(result);
        };

        fetchData();
    }, [id, getMyThing]);
}

或者如果您不想引入 async 函数:

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
    const { id } = useParams();

    const [myThing, setMyThing] = useState(null);

    useEffect(() => {
        getMyThing()
            .then(result => setMyThing(result));
    }, [id, getMyThing]);
}

另外,请注意 [id, getMyThing] 部分,因为它很重要。这是一个依赖数组,用于确定您的 useEffect 钩子何时执行/重新执行。