如何在 useEffect 中等待 setState 直到渲染?

How to wait for setState in useEffect until render?

  let [item, setItem] = useState({});
  let [comments, setComments] = useState([]);
  useEffect(async () => {
    await axios
      .all([
        axios.get(`https://dummyapi.io/data/v1/post/${id}`, {
          headers: { "app-id": process.env.REACT_APP_API_KEY }
        }),
        axios.get(`https://dummyapi.io/data/v1/post/${id}/comment`, {
          headers: { "app-id": process.env.REACT_APP_API_KEY }
        })
      ])
      .then(
        axios.spread((detail, comment) => {
          setItem({ ...detail.data })
          setComments([...comment.data.data])
        })
      )
      .catch((detail_err, comment_err) => {
        console.error(detail_err);
        console.error(comment_err);
      });
  }, []);

我像上面那样设置。 我试图在 return() 中使用状态,但它似乎没有等待数据集。

return (
          <div>
            {item.tags.map((tag, index) => {
              return <Chip label={tag} key={index} />
            })}
          </div>
)

因为我收到这样的错误消息:Uncaught TypeError: Cannot read properties of undefined (reading 'map')。 由于我初始化 'item' 只是空 {object},所以它无法读取 'item.tags',这是由 useEffect 中的 setState 设置的。

如何等待数据集?

let [item, setItem] = useState({});

您的初始状态是一个空对象,并且总会有至少一个使用此初始状态的渲染。因此,您的代码在处于此状态时需要能够正常工作。例如,您可以在尝试使用它之前检查 item.tags 是否存在:

if (item.tags) {
  return (
    <div>
      {item.tags.map((tag, index) => {
        return <Chip label={tag} key={index] />
      })}
    </div>
  );
} else {
  return <div>Loading...</div>
}

或者,您可以更改初始状态,使其与加载完成后的形状相同:

let [item, setItem] = useState({ tags: [] });

一般来说,它会设置状态 isFetched 以确定来自 api 的数据是否准备就绪。而当isFetched等于true时,表示item.tags有值。

const [isFetched, setIsFetched] = useState(false);
useEffect(async () => {
  await axios.all(...).then(() => {
    ...
    ...
    setIsFetched(true);
  })
}, [])

// You could return null or an Loader component meaning the api is not ready
if (!isFetched) return null;
return (
      <div>
        {item.tags.map((tag, index) => {
          return <Chip label={tag} key={index} />
        })}
      </div>
)

另一方面,您可以使用 optional chaining 来避免使用 undefined 值(即 item.tags)中的 map,正确的方法是替换 item.tags.mapitem.tags?.map.

最初,item 是空的 JSON ({})。您应该使用 optional chaining operator(?.) 轻松摆脱 null 或未定义的异常。

return (
          <div>
            {item?.tags?.map((tag, index) => {
              return <Chip label={tag} key={index} />
            })}
          </div>
)