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
请发送拉取请求。 我会审查它。
@vvakame我不能,我不明白它应该如何工作
我也是。 请与定义作者进行对话。
平@vsiao @thasner @basarat @pspeter3 @beckend
Ping/作者列表基于:
您需要显式地对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
属性,以便用户只允许将复选框作为子项传入。 这将有助于避免这些运行时错误。
最有用的评论
题:
解决方案: