Simon Logo
WritingMonthlyProjects
Simon Logo

Thanks for reading!

CC BY-NC-SA 4.0© 2019-2026 Simon Wong.

Contact

GitHubGithubXTwitterZhihu知乎WeChat微信公众号RSSRSS

Legal

隐私策略服务条款
CC BY-NC-SA 4.0© 2019-2026 Simon Wong.

On this page

On this page

ReactHooks组件设计前端架构业务组件

业务组件设计个人实践

Mar 15, 2021

前言

初衷

  • 抽离通用逻辑,避免重复搬砖

组件分类

  • 基础组件:提供基本功能,适用通用场景
  • 业务组件:在基础组件的基础上,加入特定功能,适用特定场景

组件评价标准

  • 集成复杂度:业务侧使用该组件的复杂程度

    越高越复杂

  • 控制反转(IoC):代码耦合程度

    越高耦合度越低

业务组件开发的心路历程

Stage 1: Hooks 时代之前

组件

一个受控组件,外部数据为 “单一真实来源”

jsx
class SearchTable extends React.Component {
  // 各种交互逻辑...

  render() {
    const {
      dataSource,
      loading,
      onPaginationChange,
      //...一堆原生组件的 props 和当前组件的 props
    } = this.props;

    return (
      <Fragment>
        <Form />
        <Table dataSource={dataSource} loading={loading} />
      </Fragment>
    );
  }
}
0
0
0
6
9
9
Views
Previous

从递归到树再到动态规划

Next

commonjs与es模块的互操作

You Might Also Like

  • AI 与前端月刊Feb 28, 2026
  • 前端与 AI 月刊Dec 31, 2025
  • 前端月刊Nov 30, 2025

业务侧

jsx
state = {
  loading,
  dataSource,
};

const fetchData = async () => {
  state.loading = true;
  await fetch();
  state.loading = false;
  state.dataSource = [];
};

const handleChangePage = () => {
  fetchData();
};

const doSotine = () => {
  ref.doSomething();
};

return <SearchTable ref={ref} loading dataSource onChangePage={handleChangePage} />;

优点

  • 少写点内部通用逻辑

缺点

  • 数据交互都是放在业务侧的,仍旧会有许多样板代码
  • 需要通过 ref 来操作组件事件
  • 组件臃肿,随着功能增强,越来越难维护

评价

集成复杂度:中

控制反转:中

Stage2: Hooks 初期时代

组件(Hooks)

一个集成了数据来源逻辑,功能逻辑,已经传好参数的组件的hooks

jsx
// 基础组件
const BaseSearchTable = ({ ...props }) => <Table {...props} />

// hooks
const useSearchTable = ({ fetchMethod, tableProps }) => {
  const [dataSource, setDataSource] = useState()
  const [loading, setLoaidng] = useState()
  const fetchData = await () => {
    setData()
    //... 操作逻辑
  }

  // onPageChange
  // deleteRow
  // updateRow

  // 一堆集成好的业务逻辑

 	const SearchTable = ({ props }) => {
    <BaseSearchTable
    	  dataSource={dataSource}
      	loading={loading}
      	{...tableProps}
      	{...props}
    />
  }

  return {
    SearchTable,
    dataSource,
    // ... 返回一些需要的方法、数据
  }
}

业务侧

jsx
const { SearchTable, deleteRow } = useSearchTable({
  fetchMethod: 'xxx',
  rowKey: 'xxx',
  // 其他配置
});

const handleDoSomething = () => {
  deleteRow();
};

return <SearchTable />;

优点

  • 只要知道参数是干什么用的,使用起来就非常方便。

缺点

  • hooks 逻辑肿,随着功能增强,越来越难维护。
  • 又可以向 hooks 传参、又可以向导出的组件传参,容易出问题。
  • hooks 应该是干净的,抽象的,而这里不仅复杂,还暴露了组件。

评价

集成复杂度:低

控制反转:低

Stage 3:现在

组件

一个只处理数据、内部逻辑的,返回组件所需 props 的 hooks

一个通过bind ,返回组件方法的 hooks

一个现成的集成好上面 hooks 的组件

jsx
// props hooks
const useSearchTableProps = ({ fetchMethod }) => {
  const fetchData = () => {}

	// 一堆业务操作逻辑、方法
  // deleteRow
  // updateRow

	return {
    dataSource,
    loaing,
    deleteRow,
    updateRow,
  }
}

// methods hooks
const useSearchTable = () => {
  // to bind
}

// 业务组件
const SearchTable = ({ props }) => {
  const {
    dataSource,
    loaing,

  } = useSearchTableProps({
    ...props
  })

  // bind useSearchTable({
  //  deleteRow,
  //  updateRow,
  //  dataSource,
  // })

  return (
  	<BaseSearchTable
      dataSource,
    	loaing
      // ...other props
    />
  )
}

业务侧

可以直接使用集成好的(也可以单用 hook,自己定义功能)

jsx
const searchTable = useSearchTable();

const doSomething = () => {
  searchTable.deleteRow();
};

console.log(searchTable.dataSource);

return (
  <SearchTable
    searchTable={searchTable} // bind hooks
    fetchMethod="xxx"
    {...otherProps}
  />
);

优点

  • 使用方便。

  • 因为通过 hooks 解耦,你可以只有一个 hooks,然后定制一些你想要的,手动集成基础组件,自定义程度提升。

缺点

  • 实现复杂度变高
  • 缺乏可见性,需要很好的理解 hooks 的内部逻辑

评价

(只评价集成好的 SearchTable,而非 hooks)

集成复杂度:低+

控制反转:低

总结

  • 业务组件:应该是低集成复杂度,提高业务编写效率,但是相对的代价是控制反正程度也会低
  • 想要更多的控制权,就会增加业务集成复杂度
  • 基础组件库:会为了更好的通用性,更低的耦合度,带来高的复杂度