Quick question for react gurus ;)
React.Children.only is one of its top-level apis, and is very commonly used by react-redux (<Provider />
) and React Router (<Router />
) to inject store/router as context, what's the reason behind this, why not simply return props.children
? Seems something to do with JSX?
EDIT: Please don't explain what is React.Children.only, i am asking for why using it instead of props.children, which seems more powerful/flexible.
As pointed out in the docs
Verifies that children has only one child (a React element) and returns it. Otherwise this method throws an error.
So now why is it helpful over just using props.children
?
The main reason is it's throwing an error, thus halting the whole dev flow, so you cannot skip it.
This is a handy util that enforces a rule of having specifically and only one child.
Of course, you could use propTypes
, but that will only put a warning in the console, that you might as well miss.
One use case of React.Children.only
can be to enforce specific declarative interface that should consist of one logical Child component:
class GraphEditorEditor extends React.Component {
componentDidMount() {
this.props.editor.makeEditable();
// and all other editor specific logic
}
render() {
return null;
}
}
class GraphEditorPreview extends React.Component {
componentDidMount() {
this.props.editor.makePreviewable();
// and all other preview specific logic
}
render() {
return null;
}
}
class GraphEditor extends React.Component {
static Editor = GraphEditorEditor;
static Preview = GraphEditorPreview;
wrapperRef = React.createRef();
state = {
editorInitialized: false
}
componentDidMount() {
// instantiate base graph to work with in logical children components
this.editor = SomeService.createEditorInstance(this.props.config);
this.editor.insertSelfInto(this.wrapperRef.current);
this.setState({ editorInitialized: true });
}
render() {
return (
<div ref={this.wrapperRef}>
{this.editorInitialized ?
React.Children.only(
React.cloneElement(
this.props.children,
{ editor: this.editor }
)
) : null
}
</div>
);
}
}
which can be used like this:
class ParentContainer extends React.Component {
render() {
return (
<GraphEditor config={{some: "config"}}>
<GraphEditor.Editor> //<-- EDITOR mode
</GraphEditor>
)
}
}
// OR
class ParentContainer extends React.Component {
render() {
return (
<GraphEditor config={{some: "config"}}>
<GraphEditor.Preview> //<-- Preview mode
</GraphEditor>
)
}
}
Hope this is helpful.