question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Children.only is inconsistent with Children.count

See original GitHub issue

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

const children = [<div />];

React.Children.count(children);
// => 1

const child = React.Children.only(children);
// => Error('React.Children.only expected to receive a single React element child.')

Repro in CodeSandbox here: https://codesandbox.io/s/1vonwo4807

What is the expected behavior?

It’s excepted that React.Children.only return the one and only element of the array (and not throw).

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

React 16.2.0

I’m not certain if this is the behavior prior to React 16 (pre-Fiber), but Fiber supports and encourages the use of fragments (i.e., arrays of elements); as such, this issue is much more likely to be encountered in React 16 onward.

Furthermore, the above code just reads like something is wrong.

How many children do I have? 1. May I have the only child? No, I expected you to only have one child. Um, okay.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

9reactions
jamesreggiocommented, Feb 2, 2018

Thanks for chiming in.

I’m well aware of how to work around this limitation, but I’m questioning why the limitation exists.

As stated in the docs for React.Children:

React.Children provides utilities for dealing with the this.props.children opaque data structure.

We’re supposed to treat children as opaque because the same element hierarchy can take on several representations.

For example, the following element hierarchies are the same to React:

const element = (
  <div>
    <span>Foo</span>
  </div>
);

const element = (
  <div>
    {
      [<span>Foo</span>]
    }
  </div>
);

The first of these would return <span>Foo</span> from React.Children.only, but the latter would not, despite producing the same virtual DOM.

This concern is all the more relevant given the new support in React 16 for arrays and fragments wherever an element is expected. I find it especially confusing that these are purported to be the same conceptually, but behave differently as far as Children.only is concerned:

const element = [
  <span>Foo</span>
];

const element = (
  <Fragment>
    <span>Foo</span>
  </Fragment>
);

If the answer is “Look at the type of this.props.children and manually unwrap the value,” then children is no longer opaque, and I might as well ditch the React.Children utilities, especially since I’m not sure if they’re going to lie to me.

I think the only justification for no-action here is a dogmatic concern for backwards compatibility.

1reaction
gaearoncommented, Aug 9, 2018

React.Children utilities are in general not very consistent with each other. They’re also a symptom of lacking primitives features in React — typically solutions using React.Children have other flaws and could be implemented more cleanly if React allowed some way to “call through” components. That’s not to say we’re never willing to change them, but it feels like the backwards compatibility cost is high, and it’s not clear this is worth doing, compared to creating other more idiomatic and powerful ways to address the same use cases.

Speaking of this specific issue, it’s naming that’s the problem. React.Children.only wasn’t intended to guarantee one child per se, but a safe downcast to ReactElement. The intention was that if you have arbitrary children, you could use React.Children.only to be sure you’re dealing with an element (and get a runtime invariant if you’re not). This can be handy in cases where the component doesn’t support dealing with multiple children, and wants to make it explicit early. In that case even passing a single-item array should be a violation because your array might be dynamic, and you might not discover the length limitation until deploying to production. So it’s handy to be able to throw on every array (as well as anything else that’s not an element), and that’s what React.Children.only gives you. Perhaps React.Children.toElementOrThrow() would be a more accurate name but I think that ship has sailed, and changing it now isn’t worth the effort.

Again, we do want to provide a better story here. But there are more fundamental flaws in Children API (e.g. that it can’t “see through” user-defined components, which, unlike the Fragment issue you pointed out, can’t be worked around in userland at all) which seem more worthy to address. We’ll try to avoid the same mistakes in any new APIs though.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How To Help Your Children Handle An Unreliable Parent
Explain that their other parent has personal issues that make it hard for them to be consistent. Tell them if they want to...
Read more >
Why Does Consistency Matter in Parenting?
Consistency between parents and others caregivers is important for child development and to decrease child anxiety.
Read more >
When a Parent is Being Inconsistent with Their Visitation
Some parents actually choose to not engage in visitation entirely! No matter the situation, this can become difficult on your child.
Read more >
Child Support and Parenting Time Orders
It is often noted that the more time a noncustodial parent spends with their child, the more child support will be paid.
Read more >
A Father's Impact on Child Development
Just as there are many positive aspects to father involvement, the effects of father absence can be detrimental as well. Father Absence.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found