Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add React.Children.isRenderable #11

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions text/0000-add-react-children-is-renderable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
- Start Date: 2018-01-10
- RFC PR: (leave this empty)
- React Issue: (leave this empty)

# Summary

Add React.Children.isRenderable() method which returns `boolean` depending
on whether a passed child returns `ReactNode` or not.

# Basic example

`React.Children.isRenderable` lets us easily detect children without UI.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would perhaps revise the naming to something like React.Children.hasRenderedOutput. Components that render nothing are still "renderable" if that makes sense.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

```js
const MaybeWrapper = ({children}) =>
React.Children.map(children, child =>
React.Children.isRenderable(child)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why you want this method on React.children and not React.isRenderable?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be convenient when we use it for whatever is passed to children prop, although my own example provides a workaround for this situation. I agree, that this is an arguable detail.

? <Wrapper>{child}</Wrapper>
: child
)
```

# Motivation

Given a component which renders markup or `null` depending on its props there
are cases when we want to know whether it renders something:
- if we need to wrap it with layout, or draw something else around or add
animations, etc and don't want to break styling with excessive wrappers;
- if we want to show a placeholder when the component has not been rendered;
- if we want to count actually visible children in an array.

`React.Children.isRenderable` would allow us easily check if a component
renders anything without messing up it's internals. It is simple, useful and
plays well with other methods from `React.Children` namespace.

# Detailed design

A method takes a `child` component instance, finds it's corresponding fiber and

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it's -> its

checks whether it has a `stateNode`. If a `stateNode` exist, the method returns
`true`, else it starts recursively repeat this process on a child fiber and it's
siblings until it finds a non-empty `stateNode` containing a DOM node, otherwise
it returns `false`.

# Drawbacks

Why should we *not* do this? Please consider:

- the proposed feature can be implemented in user space
Copy link

@gnapse gnapse Feb 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on how would this be achievable in user space? Perhaps if it can be shown that it would be complex enough to do so, it could help your case.

For instance, it may be naivety on my side, but I'm not sure how isRenderable(child) is different than simply doing child != null. Perhaps this will detect the rendering of blank strings and return false for those too? Or perhaps it'll do the same that that condition does, but more efficiently? I'm not entirely familiar with fiber internals to fully make sense of the details in the "Detailed design" section above.


# Alternatives

Obviously, we could store the result of the rendering condition in the
component's state, update it when props change and check passing handler from
a parent or we could hoist condition to a parent but we might not want do
anything of that because:
- the component may receive props from context (e.g. from Redux store via
`connect` function) so we cannot hoist the condition;
- adding props for "renderability" handler to the component may break coherence;
- we may not be able to modify the component's internals (e.g. it is from a 3rd
party library);
- we don't want to add complexity for a trivial action (e.g. we have
a stateless functional component with rendering condition. Do we really need
to make it stateful just to check if it renders anything?) or lose
convenience (stateless conditional components are quite eloquent).
We could also use refs to check if a component was rendered, but this is even
more messy solution than previous.

# How we teach this

To understand why this feature is useful and how it should be used, a user
must be familiar with core React concepts covered in [React Components, Elements, and Instances](https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html)

# Unresolved questions

Another possible solution might be to create a method, which returns a complete
Node (or `null`), rendered by the passed child though such functionality may
lead to misuse and confusion. Also that would probably have some performance
drawbacks because it requires to traverse deeper into a fiber.

The name of this method might be reconsidered. The alternatives are:
`hasNode`, `hasReactNode`, `rendersNull` (then should return `false` if
renders anything).