使用高阶组件消除React组件代码冗余的方案咨询
更优的React逻辑复用方案推荐
针对你要复用数据获取、加载状态渲染的需求,有几种更符合React组件范式的方案,比你当前的传参函数方案更易于维护和扩展:
1. 标准高阶组件(HOC)
高阶组件的核心是接收一个组件,返回一个新组件,新组件封装复用逻辑,把处理好的数据传递给被包裹的组件,完全贴合你最初想使用HOC的需求:
import { CircularProgress } from "@mui/material"; import React from "react"; function getData(id: number) { return id === -1 ? undefined : `Value for ${id}`; } // 定义HOC:接收被包裹组件,返回带数据逻辑的新组件 const withData = <P extends { data: string }>(WrappedComponent: React.ComponentType<P>) => { return (props: Omit<P, "data"> & { id: number }) => { const data = getData(props.id); if (!data) return <CircularProgress />; // 把数据传给被包裹组件,同时透传其他props return <WrappedComponent {...props as Omit<P, "data">} data={data} />; }; }; // 定义仅负责渲染的基础组件 function BaseComponent(props: { data: string; componentName: string }) { return <>Showing {props.data} in component {props.componentName}</>; } // 生成带数据逻辑的组件 const ComponentA = withData(BaseComponent); const ComponentB = withData(BaseComponent); // 使用方式:直接作为组件传入id和其他props // <ComponentA id={1} componentName="A" /> // <ComponentB id={2} componentName="B" />
这种方案可以快速给多个组件注入数据逻辑,符合React社区对HOC的通用认知。
2. Render Props 组件
Render Props 通过组件的props传递渲染逻辑,灵活性更高,不需要创建新的组件,直接在使用时定义渲染内容:
import { CircularProgress } from "@mui/material"; import React from "react"; function getData(id: number) { return id === -1 ? undefined : `Value for ${id}`; } // 封装数据逻辑的Render Props组件 const DataLoader = ({ id }: { id: number; children: (data: string) => JSX.Element }) => { const data = getData(id); if (!data) return <CircularProgress />; return children(data); }; // 使用方式:直接在JSX中使用,传入id和渲染逻辑 // <DataLoader id={1}> // {(data) => <>Showing {data} in component A</>} // </DataLoader> // <DataLoader id={2}> // {(data) => <>Showing {data} in component B</>} // </DataLoader>
这种方案适合需要动态调整渲染逻辑的场景,避免了创建过多包装组件。
3. 自定义Hook(推荐)
React Hooks出现后,自定义Hook是复用状态逻辑的首选方案,它更轻量化,且能让组件保留自己的渲染控制权:
import { CircularProgress } from "@mui/material"; import React from "react"; function getData(id: number) { return id === -1 ? undefined : `Value for ${id}`; } // 自定义Hook:封装数据获取逻辑 function useData(id: number) { // 如果是异步数据,可加入useState和useEffect处理,这里同步获取直接返回 const data = getData(id); const isLoading = !data; return { data, isLoading }; } // 使用Hook的组件 function ComponentA(props: { id: number }) { const { data, isLoading } = useData(props.id); if (isLoading) return <CircularProgress />; return <>Showing {data} in component A</>; } function ComponentB(props: { id: number }) { const { data, isLoading } = useData(props.id); if (isLoading) return <CircularProgress />; return <>Showing {data} in component B</>; }
自定义Hook的优势在于逻辑复用颗粒度更细,组件代码更直观,同时支持异步数据获取(只需在Hook中加入useEffect处理异步请求),扩展性最强。
内容的提问来源于stack exchange,提问作者Maxence Cramet
相关产品推荐
相关产品推荐

