通过反应路由器组件安装反应自定义钩子无限循环

时间:2021-02-01 05:08:41

标签: reactjs context-api

我尝试实现自定义 useBreadcrumbs 钩子,它应该在路由器组件挂载时添加面包屑条目,并在卸载时删除该条目。 我尝试使用上下文提供程序和一些方法来做到这一点:

const BreadcrumbsProvider: FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [breadcrumbConfiguration, setBreadcrumbConfiguration] = useState<
    BreadcrumbOptions
  >({} as BreadcrumbOptions);

// adds 1 entry to the entries array end
  const updateBreadcrumbs = useCallback((path: string, name: string) => {
    setBreadcrumbConfiguration((prev) => {
      const entries = prev?.entries || [];
      if (
        !entries.some((entry) => entry.path === path && entry.name === name)
      ) {
        return {
          ...prev,
          entries: [...entries, { path, name }],
        };
      }
      return { ...prev };
    });
  }, []);

//removes entry
  const revertOnUnmount = useCallback((path: string, name: string) => {
    setBreadcrumbConfiguration((prev) => {
      const entries = prev?.entries || [];
      if (entries.some((entry) => entry.path === path && entry.name === name)) {
        return {
          ...prev,
          entries: [...entries.slice(0, entries.length - 1)],
        };
      }
      return { ...prev };
    });
  }, []);

  const val = useMemo(() => {
    return { breadcrumbConfiguration, revertOnUnmount, updateBreadcrumbs };
  }, [breadcrumbConfiguration]);

  return (
    <BreadcrumbContext.Provider value={val}>
      {children}
    </BreadcrumbContext.Provider>
  );
};

export default BreadcrumbsProvider;

和我的 useBreadcrumbs 钩子:

export const useBreadcrumbs = (path: string, name: string) => {
  const {
    breadcrumbConfiguration,
    updateBreadcrumbs,
    revertOnUnmount,
  } = useContext(BreadcrumbContext);

  useEffect(() => {

    updateBreadcrumbs(path, name);

    return () => revertOnUnmount(path, name);
  }, []);

};

所以在我的组件中,我是这样使用的:

const NestingExample = memo(() => {
  console.log('render app');
  return (
    <Router>
      <BreadcrumbsProvider>
        <div>
           <Breadcrumbs /> 
          <ul>
            <li>
              <Link to="/topics">Topics</Link>
            </li>
          </ul>
          <Switch>
            <Route path="/topics">
              <Topics />
            </Route>
          </Switch>
        </div>
      </BreadcrumbsProvider>
    </Router>
  );
});

const Home = memo(() => {
  console.log('render home page');
  useBreadcrumbs('/path-to-home', 'home page'); // <--
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
});

const Topics = memo(() => {
  let { path, url } = useRouteMatch();

  useBreadcrumbs('/path-to-topics', 'topics page'); // <--

  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <Link to={`${url}/rendering`}>Rendering with React</Link>
        </li>
        <li>
          <Link to={`${url}/components`}>Components</Link>
        </li>
      </ul>

      <Switch>
        <Route exact path={path}>
          <h3>Please select a topic.</h3>
        </Route>
        <Route path={`${path}/:topicId`} component={() => <Topic />} />
      </Switch>
    </div>
  );
});

const Topic = memo(() => {
  let { topicId } = useParams();

  useBreadcrumbs('/inner-topic', `inner topic ${topicId}`); // <--
  return (
    <div>
      <h3>{topicId}</h3>
    </div>
  );
});

const Template: Story<BreadcrumbsProps> = () => {
  return <NestingExample />;
};

export const Test: Story<BreadcrumbsProps> = Template.bind({});

所以,它适用于第一级路线,但是当我点击带有确切主题的内部路线时 - 它进入无限循环

附注。由于某些情况,我在故事书中这样做。 PSS。 sry for textwall

0 个答案:

没有答案