使用useContext组合组件管理数据和布局(react)

57 阅读2分钟

现在有个场景,列表页展示的文章和详情页展示的文章没有太大差异,比如列表页不显示正文,而详情页显示全部,两个页面展示的时间位置需要稍微调整。

列表页布局

image.png

详情页布局

image.png

可以看到列表页不需要显示正文,同时时间的位置需要调整,如果把整体作为一个组件,应对这种布局上 有差异的场景,调整起来就不太方便。

解决方法:可以使用useContext作为管理状态的根组件,标题、时间、描述、图片、正文等分别 作为一个子组件,而不是在一个组件写死,这样可以根据需要很灵活地调整布局。

创建一个context管理数据,子组件使用useContext使用数据,为了子组件使用方便,把context在一个函数内导出,同时限制子组件必须在根组件Root内,否则抛出错误。

import { createContext, useContext } from "react";
const ArticleContext = createContext(null);
function useArticleContext() {
  const context = useContext(ArticleContext);
  if (!context) {
    throw new Error("子组件必须位于Root根组件内!");
  }
  return context;
}
export { ArticleContext, useArticleContext };

根组件

根组件中传入供子组件使用的数据

<ArticleContext.Provider value={article}>
  {children}
</ArticleContext.Provider>

标题组件

export default function Title() {
  const { title } = useArticleContext();
  return (
    <div className={styles.title}>
      <div>{title}</div>
    </div>
  );
}

时间组件

export default function Time() {
  const { createdTime } = useArticleContext();
  return <div className={styles.time}>{createdTime}</div>;
}

为了方便管理可以在一个文件统一导出根组件及子组件

import Root from "./Root";
import Time from "./Time";
import Title from "./Title";
const components = {
  Root,
  Title,
  Time,
  ...
};
export default components;

然后在需要的地方使用

列表页:标题和时间在同一行显示。

<Components.Root article={article}>
  <div className={styles.header}>
    <Components.Title></Components.Title>
    <Components.Time></Components.Time>
  </div>
</Components.Root>

详情页:标题和时间在不同行显示。

<Components.Root article={article}>
    <Components.Title></Components.Title>
    <Components.Time></Components.Time>
</Components.Root>

可以看到使用起来很方便,可以随意排列这些子组件达到不同布局的目的,而一旦子组件在Root根组件外面使用,就会报错。

image.png