之后,在各个流程的相应位置,都通过 pluginContainer 执行相应的钩子函数即可:
export const TreeTable = React.forwardRef((props, ref) => { // 省略上一部分代码…… // 这里拿到了 pluginContainer const pluginContainer = usePluginContainer( { ...props, plugins: [usePaginationPlugin, useLazyloadPlugin, useIndentLinePlugin], }, pluginContext ); // 递归遍历整个数据 调用钩子 const rewriteTree = ({ dataSource, // 在动态追加子树节点的时候 需要手动传入 parent 引用 parentNode = null, }) => { pluginContainer.onRecord(parentNode); traverseTree(dataSource, childrenColumnName, (node, parent, level) => { // 这里执行插件的 onRecord 钩子 pluginContainer.onRecord(node, parent, level); }); } const rewrittenColumns = columns.map(rawColumn => { // 这里把浅拷贝过后的 column 暴露出去 // 防止污染原始值 const column = Object.assign({}, rawColumn); pluginContainer.onColumn(column); return column; }); const onExpand = async (expanded, record) => { // 这里执行插件的 onExpand 钩子 pluginContainer.onExpand(expanded, record); }; // 这里获取合并后的 components 传递给 Table const components = pluginContainer.mergeComponents() });
之后,我们就可以把之前分页相关的逻辑直接抽象成 usePaginationPlugin:
export const usePaginationPlugin: TreeTablePlugin = ( props: ResolvedProps, context: TreeTablePluginContext ) => { const { forceUpdate, replaceChildList } = context; const { childrenPagination, childrenColumnName, rowKey, indentLineDataIndex, } = props; const handlePagination = node => { // 先加入渲染分页器占位节点 }; const rewritePaginationRender = column => { // 改写 column 的 render // 渲染分页器 }; return { onRecord: handlePagination, onColumn: rewritePaginationRender, }; };
也许机智的你已经发现,这里的插件是以 use 开头的,这是自定义 hook的标志。
没错,它既是一个插件,同时也是一个 自定义 Hook。所以你可以使用 React Hook 的一切能力,同时也可以在插件中引入各种社区的第三方 Hook 来加强能力。
这是因为我们是在 usePluginContainer 中通过函数调用执行各个 usePlugin,完全符合 React Hook 的调用规则。
而懒加载节点相关的逻辑也可以抽象成 useLazyloadPlugin:
export const useLazyloadPlugin: TreeTablePlugin = ( props: ResolvedProps, context: TreeTablePluginContext ) => { const { childrenColumnName, rowKey, hasNexTKEy, onLoadMore } = props; const { replaceChildList, expandedRowKeys, setExpandedRowKeys } = context; // 处理懒加载占位节点逻辑 const handleNextLevelLoader = node => {}; const onExpand = async (expanded, record) => { if (expanded && record[hasNextKey] && onLoadMore) { // 处理懒加载逻辑 } }; return { onRecord: handleNextLevelLoader, onExpand: onExpand, }; };