React - component will not render in foreach loop? - reactjs

I have a small application when you open a tab the React Route redirects to the given component (container). And from the container i want to render the child components. I use the foreach loop to go through a list that has the props that need to be given to the child. However, the child doesn't get rendered.
I don't want to use map because i use libraries that depend on the list class.
render() {
return (
<div>
{this.state.list.ForEach((element) =>
<ChildComponent childName={element.name}
}
</div>
);
}
}

You are confusing Array.forEach with Array.map. forEach does not return anything. The correct way is:
<div>
{this.state.list.map((element, index) =>
<ChildComponent key={index} childName={element.name} />
)}
</div>
map converts the given element into another element, a component in this case. The result of calling map is an array of components that is then rendered. forEach always returns undefined therefore the result of your code is the same as writing:
<div>
{undefined}
</div>
Note that key is also necessary when rendering lists of components.

Related

Why return multiple elements in React is not allowed?

it can only return only one element tag in render.
In v16, we can render multiple elements by using an array.
so why cannot straightly write mutiple element tags in React?
render(){
return(
<div />
<div />
)
}
I mean that why cannot render multiple elements but not how to render mutiple elements.
React implementation relies on constructing a tree like structure which it uses to for reconcilation. When you return multiple elements from React elements from the render method, the assumtion that the tree will have one root node for the Component will not longer hold, hence making it difficult to process reconcilation algorithm.
Thus react gives you a limitation to provide a root node. If you return an array of elements from v16 onwards, react will internally create a dummy node as the parent.
From version 16.2 onwards React provides a React.Fragment component, that provides a cleaner syntax to return multiple elements
render(){
return(
<React.Fragment>
<div />
<div />
</React.Fragment>
)
}
React needs a parent element to render anything. You could put them in an array, or use a tool they gave for this exact purpose, the fragment component.
A fragment is just an empty node that won't show in the DOM allowing you to return multiple JSX components next to each other :
render(){
return(
<>
<div />
<div />
</>
)
}
If your linter is not a fan of this, you can use React.Fragment instead :
render(){
return(
<React.Fragment>
<div />
<div />
</React.Fragment>
)
}
The short answer to your question is... well this is just how React works and how their rendering engine is designed.
For now, multiple elements put together will not be interpreted as an array.
You can try
render(){
return[
<div> Div 1</div>,
<div> Div 2</div>,
<div> Div 3</div>,
<div> Div 4</div>
]
}

ReactJS : Render dynamic child elements inside a custom component

I've created a generic component which renders dynamic content. Idea is to render whatever child elements are provided inside the custom component. Code snippet below:-
<DropDownMenu {...profileDropDown}>
<div className="profile-drop-down-settings">
profileProps.map(function(data, index) {
<span>{data}</span>
});
</div>
</DropDownMenu>
Dropdown component (render part) :-
render() {
const config = this.props;
return (
<div class="drop-down-menu">
{this.props.children}
</div>
)
}
Now the issue is, I'm not able to run the map function. It throws an error stating it can't access the data variable. I'm new to react, am I missing anything?
I've setup a simple sandbox to showcase what you're trying to do.
In essence:
App renders Container which is given children by App
the logic for how the children are constructed are controlled by App
Container simply renders those children as is
Hope this example is a replica of what you're trying to achieve
you can try this,
<DropDownMenu {...profileDropDown}>
<div className="profile-drop-down-settings">
{ profileProps.map(function(data, index) {
return <span{data}</span>
}); }
</div>
</DropDownMenu>

Gathering a collection of elements for a basic tab switcher

Objective
I want to make a basic tab switcher with React, starting with gathering a collection of tab elements.
Error
The array of HTML elements I'm able to assemble after my code has run contains a number of null entries equal to that of the actual elements.
Attempt
I have a wrapper for the entire structure, and here is its render method:
render(){
return (
<section className={"TR-Resume " + this.state.closedClass} ref="resume">
<div className={"TR-ResumeInner " + this.state.collapsedClass} ref="resumeInner">
<header className="TR-ResumeHeader">
<h2>Resumé</h2>
<Link to="/" className="TR-ResumeClose" onClick={this.close.bind(this)}>×</Link>
</header>
<section className="TR-ResumeMain js-ResumeTabs" ref="resumeTabs">
<header className="TR-ResumeTabs">
<Tabs className="js-Tabs" resume={this.props.resume.resume} tabRef={el => this.tabs.push(el)} />
</header>
<section className="TR-ResumeContent">
<Sections tabs={this.props.resume.resume} sectionRef={el => this.sections.push(el)} />
</section>
</section>
</div>
</section>
)
}
You'll notice I am using the React recommended method of exposing refs of children components to parents. I am appending each to a property of the parent component: tabRef={el => this.tabs.push(el)}
I understand I am re-declaring that collection every time the block renders, so to prevent appending the same elements to the collection, I'm clearing it in componentWillUpdate() lifecycle event:
componentWillUpdate() {
this.tabs.length = 0;
}
Result
My plan is to attach click events to the tabs to switch between panels, but I can't get that far, because by the time the componentDidUpdate() event fires, this is was is output in the array when I log it to the console:
[ null, null, null, null, a.TR-ResumeTab.js-Tab.TR-ResumeTab_active, a.TR-ResumeTab.js-Tab, a.TR-ResumeTab.js-Tab, a.TR-ResumeTab.js-Tab ]
Is there a better way to do this? Am I doing something wrong?
I plan to take these to animate tab panel with GSAP and want to avoid using jQuery.
Any help would be appreciated.
This is an issue with how you are using refs. When you do an inline ref declaration ( ref={ref => this.input = ref} ), the first time the component renders, it will receive a null value. Then on the second render, the refs will be correctly assigned. So that is why you first see the 4 null values, and then the 4 correct values.
To get around this, you should supply a class method to the ref prop instead of an inline function.
Example:
This:
render() {
return (
...
<Tabs className="js-Tabs" resume={this.props.resume.resume} tabRef={el => this.tabs.push(el)} />
...
)
}
Should be:
applyRef = ref => {
this.tabs.push(ref);
}
render() {
return (
...
<Tabs className="js-Tabs" resume={this.props.resume.resume} tabRef={this.applyRef} />
...
)
}
When you use a class method to apply a ref, it only gets called once when the actual element has been added to the dom, so you shouldn't get the initial null values anymore.

Pass JSX to child, and have the child edit JSX props?

How can <MyList> add prop myListProp={true} to <SomeComponent1>?
I want MyList to manage props, and not the class where this JSX is declared (theCurrentClass)
<div className='theCurrentClass'>
<MyList>
<SomeComponent1 />
<OtherComponent2 />
<WowComponent3 />
</MyList>
</div>
Is cloneElement the only way?
I need to constantly update these props / styles, and don't want to continuously clone the JSX.
This does seem to be accounted for, both with cloneElement and JSX.
https://facebook.github.io/react/docs/react-api.html#cloneelement
return this.props.children.map((child, index) => {
return React.cloneElement(child, {
...child.props,
});
});
return this.props.children.map((child, index) => {
return ( <child.type {...child.props}></child.type> );
});
I can interface with the element by adding props the same way I do with any rendered element
NOTE: requestAnimationFrame loops should only edit the ref (passed back from the child in a callback on didMount), and rarely update props unless you want to deal with all the React "smart" analysis bogging down the 60fps

When should I be using React.cloneElement vs this.props.children?

I am still a noob at React and in many examples on the internet, I see this variation in rendering child elements which I find confusing. Normally I see this:
class Users extends React.Component {
render() {
return (
<div>
<h2>Users</h2>
{this.props.children}
</div>
)
}
}
But then I see an example like this:
<ReactCSSTransitionGroup
component="div"
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{React.cloneElement(this.props.children, {
key: this.props.location.pathname
})}
</ReactCSSTransitionGroup>
Now I understand the api but the docs don't exactly make clear when I should be using it.
So what does one do which the other can't? Could someone explain this to me with better examples?
props.children isn't the actual children; It is the descriptor of the children. So you don't have actually anything to change; you can't change any props, or edit any functionality; you can only read from it. If you need to make any modifications you have to create new elements using React.CloneElement.
https://egghead.io/lessons/react-use-react-cloneelement-to-extend-functionality-of-children-components
An example:
main render function of a component such as App.js:
render() {
return(
<Paragraph>
<Sentence>First</Sentence>
<Sentence>Second</Sentence>
<Sentence>Third</Sentence>
</Paragraph>
)
}
now let's say you need to add an onClick to each child of Paragraph; so in your Paragraph.js you can do:
render() {
return (
<div>
{React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
onClick: this.props.onClick })
})}
</div>
)
}
then simply you can do this:
render() {
return(
<Paragraph onClick={this.onClick}>
<Sentence>First</Sentence>
<Sentence>Second</Sentence>
<Sentence>Third</Sentence>
</Paragraph>
)
}
Note: the React.Children.map function will only see the top level elements, it does not see any of the things that those elements render; meaning that you are providing the direct props to children (here the <Sentence /> elements). If you need the props to be passed down further, let's say you will have a <div></div> inside one of the <Sentence /> elements that wants to use the onClick prop then in that case you can use the Context API to do it. Make the Paragraph the provider and the Sentence elements as consumer.
Edit:
Look at Vennesa's answer instead, which is a better explanation.
Original:
First of all, the React.cloneElement example only works if your child is a single React element.
For almost everything {this.props.children} is the one you want.
Cloning is useful in some more advanced scenarios, where a parent sends in an element and the child component needs to change some props on that element or add things like ref for accessing the actual DOM element.
In the example above, the parent which gives the child does not know about the key requirement for the component, therefore it creates a copy of the element it is given and adds a key based on some unique identifier in the object. For more info on what key does: https://facebook.github.io/react/docs/multiple-components.html
In fact, React.cloneElement is not strictly associated with this.props.children.
It's useful whenever you need to clone react elements(PropTypes.element) to add/override props, without wanting the parent to have knowledge about those component internals(e.g, attaching event handlers or assigning key/ref attributes).
Also react elements are immutable.
React.cloneElement( element, [props], [...children] ) is almost equivalent to:
<element.type {...element.props} {...props}>{children}</element.type>
However, the children prop in React is especially used for containment (aka composition), pairing with React.Children API and React.cloneElement, component that uses props.children can handle more logic(e.g., state transitions, events, DOM measurements etc) internally while yielding the rendering part to wherever it's used, React Router <switch/> or compound component <select/> are some great examples.
One last thing that worth mentioning is that react elements are not restricted to props.children.
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
They can be whatever props that makes sense, the key was to define a good contract for the component, so that the consumers of it can be decoupled from the underlying implementation details, regardless whether it's using React.Children, React.cloneElement, or even React.createContext.

Resources