React able to render arrays of elements without using .map? - reactjs

I'm going through a book to better learn React and came across a surprising example. I previously thought that in order to render an array of anything in React, we need to map each element of the array, and pass them keys (I know keys aren't absolutely mandatory but a best practice so React knows which element to re-render upon change.)
But here is a working example of an array being rendered without needing to do anything special to it:
const Tail = ({number, children}) => (
<div>
Last {number} children:
{React.Children.toArray(children).slice(-number)}
</div>
)
Is this something special about children? Why is React able to render an array like this? There aren't even keys specified!

So React.Children provides utilities like toArray, map, forEach etc for dealing with the children props data structure.
In this case the toArray:
Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
Here are the docs if you want to read more: https://reactjs.org/docs/react-api.html

Related

Why is using React Context better than just passing around a props object?

I've been reading about the advantages of using Context in React and I am unconvinced. I'm wondering if there's something I've missed.
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
What's the hassle in creating a props object in the main component and just passing it around among the underlings? Something like:
// do this once at top level (I'm assuming [foo, foo_set] and [bar, bar_set] are state variables):
const props = {foo, foo_set, bar, bar_set, thisAndThat, theOther, whatever, etcAndEtc}
// including one component
<MyComponent1 {...props } />
// including another
<MyComponent2 {...props } />
(Maybe better to use another name than props for this object, as the components can have other properties. Anyway.)
Then in MyComponent1 you can access all the props you want, or not access them. Either:
...
const MyComponent1 = (props) => {
...
// here we can use any props we need, props.bar, props.bar_set, props.theOther for example
const localVar = props.bar * 2;
props.bar_set(localVar);
// this changes the value of bar throughout the app
...
}
the advantage of the above, as I see it, is that you can pass around the props object to other sub-sub-components and not worry about whether you have anything missing.
Or:
...
const MyComponent1 = ({bar, bar_set, theOther }) => {
...
// here we can use bar, bar_set, theOther in the same example
const localVar = bar * 2;
bar_set(localVar);
...
}
The advantage of this option being that the syntax is shorter.
So my point is why not just use the standard JavaScript syntax? Why introduce new concepts when there are plenty to assimilate to do all sorts of other things?
Consider a fairly common case for most applications: You have authentication information (eg, the current user), a routing library (eg, react-router), and a theme object (what colors to use). These are needed in components scattered throughout the app.
You want to render a button somewhere down at the tip of the component tree. It's going to show the user's avatar, so it needs the authentication data. It's going to navigate when clicked, so it needs the navigate function from the routing library. And it needs to style itself according to the theme.
This certainly can be done through props, but in order for the button to get the props, every component in the chain above it must get and forward those props too. This could be many components deep, like page component -> section component -> table -> row -> widget -> button, and most of them don't need that information for themselves, so they're just taking the props in order to forward it along.
And you can easily imagine cases where there are more than 3 pieces of data that are needed across the app.
What's the hassle
Most people find this "prop drilling" to be a hassle, but let's assume you don't. You still have the problem that it has bad performance. If every component must receive the full set of "global" values that the app might need, then any time anything changes, the entire app must rerender. Optimizations like react.memo become effectively useless. You will get much better performance if you only pass the props you need.
Easier to edit code (You don't have to delete for example unused variable)
Better redability (You dont see unnescesary variables, and You see which component is using variables)
Lesser performance waste (preventing from consuming unnescesarry variables)
Suppose You got 10 descendants in - You would have to pass one variable through 10 of components.
What if some could have the same variable name ? You would have to edit Your passed variable for a while, then edit back later.
To sum up:
Using Context more efficient than stuffing everything into a single object variable, because it avoids re-rendering the whole app when anything changes.
People think passing a single variable around is more hassle than introducing specific syntax.
Context also allows you to have different values for the same variable in different parts of the app. This is shown here (the best explanation IMHO) : https://beta.reactjs.org/learn/passing-data-deeply-with-context
The above article also specifies that sometimes passing props is the best solution. It gives a list of use cases for context, and the advantages provided in each case.

Multiple JSX elements with react

If we want to write multiple JSX elements we must wrap it with parent element or React Fragment element to be rendered successfully , Is there any way to write multipe jsx elements without need to wrap it with any parent or fragment element (like maybe make the fragment by default behind the scene without need to write it ) ,
function CustomBtn() {
return (
<h1>CustomBtn</h1>
<h1>CustomBtn</h1>
)
}
i know this will give Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag
i know that it's useless , because we can just use react fragment , but it's like a training task to dig deeper into react configuration
i think in babel , webpack or react dom packages but i can't solve it , any ideas ?
Thanks
This is a good idea. But this is not customizable for the following reason.
React team made the interface of a component to be a single ReactNode. But for some functions, they also allow for an array of nodes, ReactNode[]. To be honest, internally they do support array, otherwise you won't be able to do {arr.map(v => <div />).
Therefore this is not something that you like or not, it's the interface definition of a React component. Imagine you design the component, you can choose to accept an array or a single. If you were the author, you could make that happen ;)
NOTE:
deep down there's another reason, each component accepts a ref. The ref is the DOM element reference, so a single mapping from one ref to a single React node is a more straightforward implementation.
You can return array:
function CustomBtn() {
return [
<h1>CustomBtn</h1>,
<h1>CustomBtn</h1>
]
}

ReactJS wrap children, and descendents, see-through a component

I'm trying to find a good way to produce a layout control that wraps all it's DOM children, let's say in a div tag for simplicity. The basic approach is to use React.Children.map, but this is posing some problems with constructed lists of children via components -- it cannot see inside Components.
For example, say I have this structure, where the final DOM result should be a <ul> with several <li> elements. The Item* components themselves do not know they are in a list.
<WrapItems>
<ItemA/>
<ItemB/>
<ItemC/>
<ItemD/>
</WrapItems>
I can produce the DOM result I want by iterating the react children and wrapping them in a li. However, some of these items are shared between several controls, motivating me to create a common component.
<WrapItems>
<ItemA/>
<CommonItems/>
<ItemD/>
</WrapItems>
Where CommonItems ends up rendering:
<>
<ItemB/>
<ItemC/>
</>
The issue is that I cannot wrap ItemB and ItemC anymore, since React.Children will walk iterate the immediate children*.
Essentially I want CommonItems to be transparent and expose it's children directly to the WrapItems control, so that it can wrap them correctly. Is there a way to do this?
I've tried an approach where I replace the component with a useCommonItems function that returns an array of items instead. In some cases this can work, but in others it becomes a challenge, and a performance concern. Some of these parts are conditional, and the use approach forces them to all end up non-conditionally evaluated, along with all their use... functions in turn.
*Note, I'm aware that React.Children.map does not iterate over fragments, but I can solve that part by doing my own Children.map that descends into fragments. The issue in this question is about iterating over the children of components. The solution may be related, I'm not sure.

Get Call Depth Inside React Component

I'm trying to make a scene graph in React that supports nesting components. Something along the lines of:
<SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
</SceneNode>
When a SceneNode is mounted I need a way for it to know at what "depth" it is. Is there a way within a component to access that information? e.g.:
function SceneNode({children}:{children:ReactNode}) {
const depth = useCallDepth(); // <- some magic function that lets me know the level of nesting for this node
return <div>{children}</div>
}
NOTE: I've tried the following:
Context: Can't get it to work without having each node create its own context but since context is referenced statically in React I can't access the dynamically created parent contexts from children.
Refs: The nesting of components should be reflected in the DOM elements they produce, but I can't figure out how to determine what the associated component is for a given DOM element - i.e. is this div a SceneNode or just a random div? (I suppose I could encode it in an attribute or id, but I was hoping for something a little cleaner and less invasive)
Manual: I can manually specify which nodes are parents (e.g. <SceneNode parent={true}/> but that's pretty error prone.
It is possible to use context for this: Demo

react: How to structure components

I am taking up react, and need some advice on how to structure my component tree.
I want to build a generic List with filters associated with it
I have:
List component: displays a list of item. Props:
Children: prop(a function) used to render each item of the list
(item) =>
<li className="list-group-item" key={item.id}>
{item.name}
</li>
list: array of object
Filter Component: bunch of input/select used to filter the list
filterList: array containing all the field names
onChange: function to call when field changes
stateValues: values of the fields (state in the above component)
ListAndFilterContainer: contains the state the filters and passes it to the list
list: list of items passed to the list component
children: function passed on to the list as children to display the items
filterList: list of fields passed to the filter component
Render of the ListAndFilterContainer:
`<div>
<FilterOnList
filterList={this.props.filterList}
filterState={this.state.filter}
onChange={this.handleFilterChange} />
<ListComponent
list={this.props.list}
title={this.props.title}
>
{this.props.children}
</ListComponent>
</div>`
Now to make it generic I want to be able to modify the markup on how the list is gonna be rendered, and how the input fields of the Filter component are gonna be rendered.
I want to be able to use the logic of a filtered list but I still want to be free on the presentation.
How could I structure it ? The easiest way I guess would be to inherit the List component and alter the render ? For example creating a CarList extends List ?
Same for the Filter component ?
Thanks
A few thoughts...
Good idea to use a container component to hold the state. This a pattern that works well for React.
It sounds like the ListComponent could just have different types of children and might not need specific handling for different list types. In other words, you might have an array of CarItem components and render it as a children of ListComponent, instead of making a separate CarListComponent. It depends on whether you really need different logic for rendering the different lists. Some visual differences, e.g. smaller row heights, can just be accomplished with CSS, so if you pass in a className prop and render it like <ul className={this.props.className}> that can handle a lot of customization.
If you do find you need separate classes for different types of list components (or items, etc) I would avoid use of "extends", mixins, and inheritance in general. This is controversial, perhaps, but IMO, Javascript on its own is too loosely typed to work with inheritance. You lose track of what is happening when things get a little complicated, e.g. "Which class did I get that function from?" If you want to use inheritance, consider typescript. Otherwise, I'd go with functional composition - just import the functions you need from modules.

Resources