2022 React 最速上手指南(八)—— 状态提升 & React fragment

289 阅读3分钟

这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战

以结果为导向,写给刚学完前端三剑客和想要了解 React 框架的小伙伴,使得他们能快速上手(省略了历史以及一些不必要的介绍)。

状态提升

虽然我们创建了一个回调函数来将信息向上共享,但我们的目标是在多个组件中共享 Search 组件的 state。

在将 stories 传递给 List 组件之前,我们需要在 App 组件中【使用用户输入来过滤列表】,所以 state 要从子组件 Search 提升到父组件 App,以便更多组件共享 state。

也就是说 Search 组件不再管理 state,只需要在用户输入后,将事件向上传递给父组件 App:

const App = () => {
  const stories = [ ... ];

    // 状态提升
  const [searchTerm, setSearchTerm] = React.useState("");

  const handleSearch = (e) => {
    setSearchTerm(e.target.value);
  };

  return (
    <div>
      <Search onSearch={handleSearch} />
      <hr />
      <List list={stories} />
    </div>
  );
};

const Search = (props) => (
  <div>
    <label htmlFor="search">Search: </label>
    <input id="search" type="text" onChange={props.onSearch} />
  </div>
);

当然你也可以将 searchTerm 作为 props 向下传递,继续在 Search 组件中展示:

const App = () => {
    ...

  return (
    <div>
      <Search onSearch={handleSearch} searchTerm={searchTerm}/>
      ...
    </div>
  );
};

const Search = (props) => (
  <div>
    <label htmlFor="search">Search: </label>
    <input id="search" type="text" onChange={props.onSearch} />
    <p>
      Searching for <strong>{props.searchTerm}</strong>.
    </p>
  </div>
);

总之如果下游的组件要使用 state,可以将其作为 props 传递;如果下游组件要更新 state,可以向下传递一个回调处理函数。【可参考 Search 组件】

然后就是通过 searchTerm 值 ,使用 JS内置的数组过滤函数 来过滤列表,同时做了【大小写不敏感】的匹配:

const App = () => {

  ...

  const searchedStories = stories.filter((story) =>
    story.title.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div>
      <Search onSearch={handleSearch} searchTerm={searchTerm} />
      <hr />
      <List list={searchedStories} />
    </div>
  );
};

Array.filter() 接收一个函数作为参数,并返回一个全新的数组。

该函数遍历数组的每一项并返回 true 或 false,如果返回 true,则代表该项满足条件,会保存到新数组中,反之则不保存,遍历完成后返回新数组。

现在你已经可以在输入框输入来进行搜索了,通过 Search 组件的回调处理函数,我们在 App 组件中更新了 state,并通过 state 过滤了列表传递给了 List 组件。

image-20220217002916399

React fragment

你可能会注意到:当我们创建 Search 组件时,必须引入一个顶层的 HTML 元素把它包起来才能渲染:

const Search = (props) => (
  <div>
    <label htmlFor="search">Search: </label>
    <input id="search" type="text" onChange={props.onSearch} />
    <p>
      Searching for <strong>{props.searchTerm}</strong>.
    </p>
  </div>
);

这是因为 React 组件返回的 JSX 虽然看起来像 HTML,但它在底层会被转换为【纯 JS 对象】,如果有多个同级的顶层元素,我们必须把它们放在数组中,而且加上 key 属性,以便从函数中返回多个对象:

// 举例
const Search = () => [
  <input key="1" />,
  <input key="2" />,
];

当然我们有另一种简洁的解决方式,就是 React fragment:

const Search = (props) => (
  <>
    <label htmlFor="search">Search: </label>
    <input id="search" type="text" onChange={props.onSearch} />
    <p>
      Searching for <strong>{props.searchTerm}</strong>.
    </p>
  </>
);

这个空的 tag 就是所谓的 fragment,像这样替换掉 div 就可以让你在 HTML 树中【不留痕迹】地对事物进行分组了。

专栏

因为参加打卡活动是每日更新,所以可能比较短小,可以关注一下 React 入门专栏

在更新完后会整合为一整篇,感谢关注和点赞!