如何支持组件的子元素任意摆放
程序员文章站
2022-03-26 13:20:53
筛选组件包含一个 button 和一个 form,button 能控制 form 的显示与隐藏。设计里 button 和 form 在一行,实现时理所当然地把这一行封装成了一个组件。但在另一个项目里,设计有区别,button 被放到了面板的右上角,之前写的组件没法复用了。 ......
一个筛选组件如下图:
筛选组件包含一个 button
和一个 form
,button
能控制 form
的显示与隐藏。设计里 button
和 form
在一行,实现时理所当然地把这一行封装成了一个组件。
但在另一个项目里,设计有区别,button
被放到了面板的右上角,之前写的组件没法复用了。
看看之前封装的组件:
function filterbar() { const [showform, setshowform] = usestate(true); return ( <div classname="container"> <button onclick={() => setshowform(pre => !pre)} > {showform ? "<<< filter" : "filter >>>"} </button> {showform && ( <form> <label> name <input /> </label> <label> ip <input /> </label> </form> )} </div> ); }
它做了以下 4 件事:
- 创建
button
, - 创建
form
, - 实现
button
和form
的联动, - 创建容器
div.container
, 对button
和form
布局。
「创建容器 div.container
, 对 button
和 form
布局」这件事导致了组件没法在新项目里复用。
能不能写一个组件,不对子元素布局,把布局的工作交给组件使用者去做?
思路是:把 div.container
去掉,把 button
和 form
的实例返回,组件变成了一个 hook。
function usefilterbar() { const [showform, setshowform] = usestate(true); return [ <button onclick={() => setshowform(pre => !pre)} > {showform ? "<<< filter" : "filter >>>"} </button>, showform ? ( <form> <label> name <input /> </label> <label> ip <input /> </label> </form> ) : ( undefined ) ]; }
function app() { const [filterbtn, filterform] = usefilterbar(); return ( <div classname="card"> <header title="users">{filterbtn}</header> {filterform} <table> <thead> <tr> <th>name</th> <th>ip</th> </tr> </thead> <tbody>...</tbody> </table> </div> ); }
如果是 class 组件没法用 hook 怎么办?
思路是:使用高阶组件,高阶组件是函数组件,可以使用 hook,然后把 button
和 form
通过 props
传递给 class 组件。
const withfilterbar = cmp => props => { const [filterbtn, filterform] = usefilterbar(); return ( <cmp {...props} filterbtn={filterbtn} filterform={filterform} /> ); };
我写这篇文章的目的不是为了记录技巧,而是希望对组件有新的思考:把「子元素关联关系 - 逻辑」和「子元素布局 - 视图」两件事拆开,让组件更灵活。