为什么 setItems 函数(useState 挂钩)在 useEffect 的函数内部使用时有效,但直接在 useEffect 内部使用时无效?

Why does setItems function (useState hook) work when used inside a function inside useEffect but not when it is used inside useEffect directly?

在示例中,为什么 setItems 在这里起作用:

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    const fetchItems = async () => {
      const result = await axios.get(
        `https://www.breakingbadapi.com/api/characters`
      );
      setItems(result.data);
    };
    fetchItems();
  }, []);

  return (
    <div>
      {items.map(item => (
        <div key={item.char_id}>{item.name}</div>
      ))}
    </div>
  );
}

https://codesandbox.io/s/boring-butterfly-2upbp

但不在此处(而是 returns 未定义 TypeError 项目):

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    const fetchItems = async () => {
      const result = await axios.get(
        `https://www.breakingbadapi.com/api/characters`
      );
      return result;
    };
    const result = fetchItems();
    setItems(result.data);
  }, []);

  return (
    <div>
      {items.map(item => (
        <div key={item.char_id}>{item.name}</div>
      ))}
    </div>
  );
}

https://codesandbox.io/s/compassionate-lake-7iji5

您必须使用 then 函数来获取结果。

fetchItems().then(result => setItems(result.data))

您在 useEffect 挂钩中声明了一个异步函数,因此 fetchItems 将 return 一个承诺。但是由于 useEffect 函数参数不接受异步函数,所以最好在设置状态之前先解决承诺

const fetchItems = async () => {
  const result = await axios.get(
    `https://www.breakingbadapi.com/api/characters`
  );
  return result;
};

const result = fetchItems(); // result is a promise.
setItems(result.data);

在上面的代码片段中,fetchItems 是一个异步函数,所以它 returns 是一个承诺。因此,当您使用 result.data 时,您正在尝试访问 Promise 上的 data,而不是解析后的值。

主要是因为fetchItemsreturn是一个承诺(async/await)。

但是还有另一个问题,因为您需要等待承诺得到解决,所以您需要将 await 添加到 fetchItems 但这无法完成,因为 useEffect 必须 return一个清理函数。

正确:

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [items, setItems] = useState([]);

  // Also it's valid to create it directly inside the useEffect
  const fetchItems = useCallback(async () => {
    const result = await axios.get(
        `https://www.breakingbadapi.com/api/characters`
    );
    setItems(result.data);
  }, [setItems])

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

  return (
    <div>
      {items.map(item => (
        <div key={item.char_id}>{item.name}</div>
      ))}
    </div>
  );
}

错误:

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [items, setItems] = useState([]);

  // WRONG: useEffect is not a clean-up function.
  useEffect(async () => { 
    const fetchItems = async () => {
      const result = await axios.get(
        `https://www.breakingbadapi.com/api/characters`
      );
      return result;
    };
    const result = await fetchItems();
    setItems(result.data);
  }, []);

  return (
    <div>
      {items.map(item => (
        <div key={item.char_id}>{item.name}</div>
      ))}
    </div>
  );
}