如何支持组件的子元素任意摆放

一个筛选组件如下图:

filter bar component v1

筛选组件包含一个 button 和一个 formbutton 能控制 form 的显示与隐藏。设计里 buttonform 在一行,实现时理所当然地把这一行封装成了一个组件。

但在另一个项目里,设计有区别,button 被放到了面板的右上角,之前写的组件没法复用了。

filter bar component v2


看看之前封装的组件:

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 件事:

  1. 创建 button
  2. 创建 form
  3. 实现 buttonform 的联动,
  4. 创建容器 div.container, 对 buttonform 布局。

「创建容器 div.container, 对 buttonform 布局」这件事导致了组件没法在新项目里复用。


能不能写一个组件,不对子元素布局,把布局的工作交给组件使用者去做?

思路:把 div.container 去掉,把 buttonform 的实例返回,组件变成了一个 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,然后把 buttonform 通过 props 传递给 class 组件。

const withFilterBar = Cmp => props => {
  const [filterBtn, filterForm] = useFilterBar();

  return (
    <Cmp
      {...props}
      filterBtn={filterBtn}
      filterForm={filterForm}
    />
  );
};

我写这篇文章的目的不是为了记录技巧,而是希望对组件有新的思考:把「子元素关联关系 - 逻辑」和「子元素布局 - 视图」两件事拆开,让组件更灵活。

posted @   apolis  阅读(439)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示