使用React钩子防止错误状态

时间:2020-09-08 08:57:43

标签: reactjs react-hooks

我有组件

import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";

const data = {
  "1": ["1a", "1b"],
  "2": ["2a"]
};

const slugs = {
  "1a": { text: "Lorem" },
  "1b": { text: "ipsum" },
  "2a": { text: "..." }
};

const ExamplePage: React.FC = () => {
  const { id } = useParams<{ id: string }>();
  const [index, setIndex] = useState(0);

  useEffect(() => {
    setIndex(0);
  }, [id]);

  console.log("state", {
    id,
    index
  });

  const slug = data[id][index];
  const text = slugs[slug].text;

  function onPrev(): void {
    if (index <= 0) {
      return;
    }

    setIndex((index) => index - 1);
  }

  function onNext(): void {
    if (index >= data[id].length - 1) {
      return;
    }

    setIndex((index) => index + 1);
  }

  return (
    <div>
      <button onClick={onPrev}>Prev</button>
      <span>{text}</span>
      <button onClick={onNext}>Next</button>
    </div>
  );
};

export default ExamplePage;

并为此路由:

<Route path="/:id" component={ExamplePage} />

实时版本:https://codesandbox.io/s/react-hooks-ewl4d

在以下情况下,此代码存在错误:

  1. 用户位于/1网址上
  2. 用户单击“下一步”按钮
  3. 用户点击指向/2网址的链接

在这种情况下,id将是"2"index将是1,但没有data["2"][1]

您会看到useEffect在这种情况下无济于事,因为useEffect不会停止当前的函数调用。

我的问题是:如何确保这种状态始终正确?

我知道我可以编写const text = slugs[slug]?.text;并解决了我的错误,但是仍然有一段时间,组件处于错误状态。我想知道是否是防止这种错误状态的方法。

在React类组件中,此问题可以通过getDerivedStateFromProps解决-您可以在https://codesandbox.io/s/react-hooks-solve-in-react-component-xo43g上实时观看

1 个答案:

答案 0 :(得分:0)

useEffect将异步运行,因此您尝试在更新索引之前设置slugtext

您可以将slugtext置于状态,然后在useEffectindex更改时使用另一个id更新它们:

const { id } = useParams();
const [index, setIndex] = useState(0);
const [slug, setSlug] = useState();
const [text, setText] = useState();

useEffect(() => {
  setIndex(0);
}, [id]);

useEffect(() => {
  const newSlug = data[id][index];
  if (!newSlug) return; // If id changes but index has not updated yet

  setSlug(newSlug);
  setText(slugs[newSlug].text);
}, [id, index]);