Skip to the content.

React模式/Composition

为了让react组件高度可组合,提供了react node分发的能力,react提供了APIprops.children、提供了在props上直接传JSX值的能力。(Specifying Children等效于在 调用 中另外传一个Specifying Attributes,语义相同,语法不同)。

Remember, components don’t have to emit DOM. They only need to provide composition boundaries between UI concerns.

样式JSX

写一个组件,看这个组件输出什么JSX,其中带有props Attributes、props.children甚至context,这样创建组件是普遍性的,是我们封装一个组件的目的。

const Header = props => (
  <h1 className='lots-of-styles-here'>
    <strong>
      <i className='something-else'>
        { props.children }
      </i>
    </strong>
  </h1>
);

<Header>Hello world</Header>

上面props.children值为最简化的HtmlElement Node,同样可以为复杂的JSX。

const Header = props => (<header>{props.children}</header>);
const Navigation = props => (<nav>Navigation</nav>);
const SearchBar = props => (<nav>Search Bar</nav>);
<Header><Navigation /></Header>
<Header><SearchBar /></Header>

Header组件并不关心他的content出现什么元素,什么JSX,这就让Header部分,只定义它自己那部分输出的JSX的样式以及交互,和通过props输出完全的解耦。用来构建UI时可以将应用拆分成独立自主完成功能且便于测试的小组件。

此处的JSX嵌套调用可以类比与函数的组合,但因为通过利用props.children组件调用嵌套起来比较清晰,所以就未存在lodash/fp/compose方法。

React这个地方内容分发的能力与Vue中的 [单个slot](http://cn.vuejs.org/v2/guide/components.html#单个-Slot) 单个插槽相似。

Plain对象JSX

多个属性分配多个插槽,下面是props.children对象的示例(Specifying Attributes同理):

const Header = props => (
  <header>
    {props.children.navigation}
    <br />
    <div>
      {props.children.searchbar}
    </div>
  </header>
);
<Header></Header>

这个拆分就不那么显得直观了,主要的作用在于分割,且可以随意分割。这就相当于提供了多插槽,与 具名slot 类似。

但是,对于除JSX对象外的一般性的Attributes值,用props.children没有太大意义,可以认定为anti-patterns,徒增代码理解难度。

函数JSX

将JSX写在对象属性上通过props.children传给调用组件,只具备了属性索引JSX,一般的,可以设置复杂的函数,调用props.children()得到相应的JSX,目前看来作用不是很大,且理解起来往往费力,例子暂不放。

属性: react元素

我们首先来讨论我们想生成的一般性组件树🌲,嵌套的APP、Header、Navigation最终生成的标记:

<App>
  <Header>
    <Navigation> ... <Navigation/>
  </Header>
</App>

最🥚疼的也是常看到的用来组合这三个组件的方法,是哪里需要就哪里调用的方式,如下anti-patterns代码实例:

// app.js
const App = () => (<Header />);

// header.js
const Header = () => (
  <header>
    <h1>Hello React</h1>
    <hr />
    <Navigation />
  </header>);
export default Header;

// navigation.js
const Navigation = () => (<nav>...</nav>);

遵从这个模式引入了以下问题:

调用组件时将嵌套的元素使用props传递给被调用组件,方式一:props.children,方式二:其他任何props:

// app.js
const App = () => {
  const title = (<h1>Hello React</h1>);
  return (
    <Header title={title}>
      <Navigation />
    </Header>
  );
};

// header.js
const Header = props => (
  <header>
    {props.title}
    <hr />
    {props.children}
  </header>
);

// navigation.js
const Navigation = () => (<nav>...</nav>);