Definitelytyped: 需要 React.Children.map() 和 React.cloneElement() 示例

创建于 2016-10-26  ·  8评论  ·  资料来源: DefinitelyTyped/DefinitelyTyped

React.Children.map()缺少一个很好的例子,我不明白如何输入:

/*
<CheckboxGroup ...>
  <Checkbox ... />
  <Checkbox ... />
  <Checkbox ... />
</CheckboxGroup>
*/

// Child
class Checkbox extends React.Component<CheckboxProps, void> {
  // ...
}

// Parent
class CheckboxGroup extends React.Component<CheckboxGroupProps, void> {
  // ...

  render() {
    const checkboxes = React.Children.map(this.props.children, checkbox =>
      React.cloneElement(checkbox, {
        name: this.props.name,
        checked: this.props.checkedValues.includes(checkbox.props.value),
        onChange: this.handleCheckboxChange.bind(this)
      })
    );

    return (
      <div>
        {checkboxes}
      </div>
    );
  }
}

(很常见的例子,见http://stackoverflow.com/a/32371612/990356)

  • 如何输入this.props.children
  • 如何输入React.cloneElement()
  • 如何输入React.Children.map()

大多数情况下,我最终会遇到以下错误: Type 'string' is not assignable to type 'ReactElement<any>' ,请参阅 #8131

最有用的评论

题:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

解决方案:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

所有8条评论

请发送拉取请求。 我会审查它。

@vvakame我不能,我不明白它应该如何工作

我也是。 请与定义作者进行对话。

您需要显式地对checkbox进行类型注释或类型断言,因为不能保证this.props.children不包含非 ReactElement 值。 例如:

React.Children.map(this.props.children, (checkbox: React.ReactElement<CheckboxProps>) => 
    React.cloneElement(checkbox) // should be ok
);

@vsiao thx 很多,它有效!

题:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

解决方案:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

@tkrotoff你也可以这样做:

    React.Children.map(this.props.children, (child: number) => {
      return child + 1
    })

这和建议的解决方案只是利用了React.Children.map不是强类型的事实。 您也可以使用any而不是Checkbox类型,因为不能保证这将是孩子的类型。 这意味着,如果有人通过传入字符串而误用了组件,则您可能会遇到运行时错误。

这个怎么样:

class Slot extends React.PureComponent {
  render () {
    return this.props.children
  }
}

const isReactElement = (obj: {}): obj is React.ReactElement<{}> => {
  return obj.hasOwnProperty('type')
}

const isSlot = (obj: {}): obj is Slot => {
  return isReactElement(obj) && obj.type === Slot
}

const getSlots = (children: React.ReactNode) => React.Children.map(children, (child: React.ReactChild): JSX.Element | null => {
  if (isReactElement(child) && isSlot(child)) {
    return child
  }

  return null
})

class ComponentWithSlots extends React.PureComponent {
  render () {
    const [header, footer] = getSlots(this.props.children)

    return (
      <div>
        {header}
        <div>
          <h1>Welcome</h1>
          <p>This is my lovely component with slots</p>
        </div>
        {footer}
      </div>
    )
  }
}

class MyComponent extends React.PureComponent {
  render () {
    return (
      <ComponentWithSlots>
        <Slot>My Header!</Slot>
        <Slot>
          <div>github: @variousauthors</div>
        </Slot>
      </ComponentWithSlots>
    )
  }
}

这将呈现:

My Header!
Welcome
This is my lovely component with slots

github: <strong i="17">@variousauthors</strong>

这种方法利用了我们 _do_ 拥有的类型信息,即ReactChild可能是ReactElement (我已经使用type来检测这一点,但您可能如果您愿意,请更加小心)。 我们还可以对Slot进行更多描述和详细说明。 我看到一个 UI 库实现了一个模式,其中类有自己的插槽。 就像是:

<Dropdown>
  <Dropdown.Header>
    <FancyIcon>My Header!</FancyIcon>
  </Dropdown.Header>
  {dropdownItems}
</Dropdown>

这样用户就清楚每个插槽的含义。 其余的孩子(那些没有被解析为槽的)被留在一个名为children的集合中并呈现一个 la car ,允许用户仍然正常使用children同时保留特殊行为自定义插槽。

编辑:React 显然有一个方法React.isValidElement ,你可以用它代替我的自定义isReactElement

编辑:您可以做的其他事情是在您的组件上键入children属性,以便用户只允许将复选框作为子项传入。 这将有助于避免这些运行时错误。

此页面是否有帮助?
0 / 5 - 0 等级