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できません、どういう仕組みなのかわかりません
私もです。 定義の作者と会話してください。
Ping @vsiao @thasner @basarat @ pspeter3 @beckend
以下に基づくping /作成者リスト:
this.props.children
ReactElement以外の値が含まれていないという保証はないため、 checkbox
明示的に型注釈または型アサートする必要があります。 例えば:
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
が強く型付けされていないという事実を利用しているだけです。 Checkbox
タイプの代わりにany
使用した方がよいでしょう。これは、それが子のタイプになるという保証がないためです。 これは、誰かが文字列を渡してコンポーネントを誤って使用すると、ランタイムエラーが発生する可能性が高いことを意味します。
これはどう:
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>
このアプローチは、私たちが持っている型情報を利用します。つまり、 ReactChild
はReactElement
可能性があります(これを検出するためにtype
を使用しましたが、必要に応じてもっと注意してください)。 Slot
よりも説明的で、詳しく説明することもできます。 UIライブラリが、クラスに独自のスロットがアタッチされているパターンを実装しているのを見ました。 何かのようなもの:
<Dropdown>
<Dropdown.Header>
<FancyIcon>My Header!</FancyIcon>
</Dropdown.Header>
{dropdownItems}
</Dropdown>
このようにして、ユーザーは各スロットの意味を明確に理解できます。 残りの子(スロットとして解析されていないもの)はchildren
というコレクションに残され、ラカートにレンダリングされます。これにより、ユーザーはchildren
通常どおり使用しながら、カスタムスロット。
編集:Reactにはどうやら私のカスタムisReactElement
代わりに使用できるメソッドReact.isValidElement
あります。
編集:他にできることは、コンポーネントにchildren
プロパティを入力することです。これにより、ユーザーはチェックボックスを子としてのみ渡すことができます。 これは、これらのランタイムエラーを回避するのに役立ちます。
最も参考になるコメント
質問:
解決: