Are keys necessary only on arrays in React? - javascript

When you have an array of components you should specify a key like this:
Example 1:
const els = losElementos.map(el => <div key={el.id}>el.siPeroNo</div>)
That's to optimize the rendering process.
But how about a component like this?
Example 2:
function fixedList() => {
return (
<div>
<div>first item on a list</div>
<div>second one</div>
</div>
)
}
There are two siblings with no keys, does having a key there would make a differece? (imagine if there's a lot of them....)
What if one is a div and the other is a section, does having a key now makes a difference?
Example 3:
function fixedListWhoDoesSecs() => {
return (
<div>
<div>first item on a list</div>
<section>second one but the type is different</section>
</div>
)
}
What about this one?
Example 4:
function someComps() => {
return (
<>
<div>first item on a list</div>
<div>second one</div>
<LeCustomTomato />
<ChefsNoubleGoal stuff={yez} />
</>
)
}
Does having the empty tag changes anything?
To summarize in one question: are keys only useful when you generate a dynamic array of components?

you need to define key prop when you are rendering an array else react will throw an error

By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
For example, when adding an element at the end of the children, converting between these two trees works well:
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
If you implement it naively, inserting an element at the beginning has worse performance.
In order to solve this issue, React supports a key attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a key to our inefficient example above can make the tree conversion efficient:
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
Now React knows that the element with key '2014' is the new one, and the elements with the keys '2015' and '2016' have just moved.

Related

Is it possible to make a Web Component List with undetermined number of slot?

I know it can be achieved using Javascript by manually separate the slot elements and put them into the DOM tree but I wonder if it's supported within the box. Something like this:
<my-element>
<div slot="items">Item 1</div>
<div slot="items">Item 2</div>
<div slot="items">...</div>
</my-element>
And the template should be like this:
<div class="items">
<div class="item"> <!-- Should be 1 item per slot -->
<p>Something else</p>
<slot name="items"></slot>
</div>
</div>
Is this only possible using slotchange and populate the items by Javascript? Is there any better solution, without Javascript or with less Javascript? Maybe there is an element similar to slot that I am not aware of?
since all slot="items" will be slotted into <slot name="items"> only with the slotchange Event can the Component Author determine what happened.
Note: You do not populate the items, the default slotting mechanism does; you can only remove items after they are slotted; but then your HTML above needs more info on which Item needs to be slotted.
Then the question remains, Why use multiple slot="items" at all then?? If a slot can take 1 item, then only assign 1 item
Imperative Slots might help out: https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Imperative-Shadow-DOM-Distribution-API.md
Update, I misunderdstood OPs question
All he needs to do is:
Create another Web Component: <slotted-item slot="items"></slotted-item>

ReactDOM dynamically rendering components from array

I want my RenderDOM to render one component for each object found in an array. I'm building the render with JSX, and my code is as follows:
ReactDOM.render((
<div className="container container-collapsed">
<Actions Units={aUnits} />
<div className="units-wrapper">
{
aUnits.forEach(u=> {
return <Unit unit={u} />
})
}
</div>
</div>
), document.getElementById("root"));
I expeted the output to be like this:
<div class="container container-collapsed">
<div class="actions-panel_true"></div>
<div class="units-wrapper">
<div class="unit1"></div>
<div class="unit2"></div>
<div class="unit3"></div>
</div>
</div>
And instead I'm getting:
<div class="container container-collapsed">
<div class="actions-panel_true"></div>
<div class="units-wrapper"><div>
</div>
I know that my foreach is working, I debbuged it. But it is not building one JSX per units as I expcted. How to I make this foreach loop return one component for each object in my array, back to the JSX i'm trying to render?
You need .map instead of .forEach to return an array so that React can render it effectively.
Also returning from the callback inside .forEach has no use since .forEach doesn't return an array. It returns undefined.
.forEach is useful when you want to change the contents of existing array without returning a new one. In React, JSX requires an array as a result of .map operation.
Also more valid points covered by #zhulien
This should do:
ReactDOM.render((
<div className="container container-collapsed">
<Actions Units={aUnits} />
<div className="units-wrapper">
{aUnits.map(unit => {
return (
<Unit key={u.key} unit={u} />
);
})}
</div>
</div>
), document.getElementById("root"));
A couple notes:
<Unit={u} />
is not a valid syntax. You are suppose to assign u to a property of the Unit component, not the component itself. Also, when rendering array of items, you should supply a key property to each item as to help React differentiate between them. You'll find more information about why this is important In the React docs.

How to progressively render react components?

I'm working with lists that will likely be in the range of 500 up to maybe 5000 items. Each item in the list will show as a component, like so:
List
render() {
return (
<div className="ItemList">
<Info items={this.props.items} />
<ul>
{this.props.items.map( item =>
<Item item={item} key={item._id} refresh={this.props.refresh} />
)}
</ul>
</div>
);
}
Item
render() {
var item = this.props.item;
return (
<li onClick={() => this.setState({showInfo: !this.state.showInfo})}
className="Item">
<h3 className={this.state.showInfo ? "item-title-bar active" : "item-title-bar"}>
<div>
<div className="item-category">
{item.category}
</div>
<div className="item-name">
{item.name}
</div>
</div>
</h3>
{this.state.showInfo &&
<ItemInfo item={this.props.item} refresh={this.props.refresh} />
}
</li>
);
}
Once one of these lists gets up to around 1000 items, it's noticeably slow when I click to show a different list. Perf tools are showing me 90-150 ms for displaying this list at 1000 or 2000 items. Not sure I can get around that as long as I'm rendering them.
So, what I'm trying to do:
Can I let the initial items update, then render others in the background, while the app remains responsive?
How can I show initial items, then load more as the user scrolls down the page?
If neither option works, I'll probably try to load a few, then add a show more or show all button at the bottom of the list. Want to make this as seamless as possible though, open to other suggestions as well.
react-virtualized would be my first choice when dealing with a virtual list. Lot of examples here: https://bvaughn.github.io/react-virtualized/#/components/List
Pretty simple if you know the heights of the items ahead of time, but can use the CellMeasurer component if you don't.

React.js - Creating Simple Accordion example

I'm relevantly new to React and I am having trouble on how to tackle this logic:
Essentially I am creating a table using flexbox, and I also want it so that when you click on one of the rows, it expands and reveals another row (for example, it will give a small description what it is about).
So far what I have is just the table.
class Application extends React.Component {
render() {
const renderDataRows = (
[
<div key={0} className='row'>
<div className='cell description'> Mortage Bill
</div>
<div className='cell amount'>$0,000,000</div>
<div className='cell amount'>$2.50</div>
<div className='cell amount'v>000%</div>
</div>,
<div key={1} className='row'>
<div className='cell description'> Electric Bill
</div>
<div className='cell amount'>$0,000,000</div>
<div className='cell amount'>$2.50</div>
<div className='cell amount'v>000%</div>
</div>,
]
)
const containerTable = (
<div className='table-container'>
{renderDataRows}
</div>
)
return (
<div>
{containerTable}
</div>
)
}
}
More specifically, what would be the best way to structure the hidden rows? Create as a child of the cells, or siblings?
I am assuming I will need state to keep in track what is current open, etc?
I've attached Codepen link to mess around
This can be done in the following way:
Let all the cells be in a single parent div and let the cell description be another sibling div (although using would be better). Put a class on the sibling div such as hidden. Not add a click handler on the cells div. Whenever this div is clicked, update the state with that div's id/key. Now use this to set the hidden class to the other divs. Compare this.state.key with the current id/key and show or hide accordingly. I am not giving the specific code.
Note: Instead of storing the divs in the renderDataRows, just put the data in it and map over it to create all the divs. That way you can easily manipulate the hidden class and any other variation in a single place without having to update it separately for each row of data.

How to avoid extra wrapping <div> in React?

Today I have started learning ReactJS and after an hour faced with the problem..
I want to insert a component which has two rows inside a div on the page.A simplified example of what I am doing below.
I have an html:
<html>
..
<div id="component-placeholder"></div>
..
</html>
Render function like this:
...
render: function() {
return(
<div className="DeadSimpleComponent">
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
)
}
....
And below I am calling render:
ReactDOM.render(<DeadSimpleComponent/>, document.getElementById('component-placeholder'));
Generated HTML looks like this:
<html>
..
<div id="component-placeholder">
<div class="DeadSimpleComponent">
<div class="DeadSimpleComponent__time">10:23:12</div>
<div class="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
</div>
..
</html>
The problem that I am not a very happy that React forcing me to wrap all in a div "DeadSimpleComponent". What is the best and simple workaround for it, without explicit DOM manipulations?
UPDATE 7/28/2017: Maintainers of React added that possibility in React 16 Beta 1
Since React 16.2, you can do this:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
This requirement was removed in React version (16.0), so now you are able to avoid that wrapper.
You can use React.Fragment to render a list of elements without creating a parent node, official example:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
More here: Fragments
Update 2017-12-05:
React v16.2.0 now fully supports rendering of fragments with improved support for returning multiple children from a components render method without specifying keys in children:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
If you are using a React version prior to v16.2.0, it is also possible to use <React.Fragment>...</React.Fragment> instead:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
Original:
React v16.0 introduced returning an array of elements in render method without wrapping it in a div: https://reactjs.org/blog/2017/09/26/react-v16.0.html
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
At the moment, a key is required for each element to avoid the key warning but this could be changed in future releases:
In the future, we’ll likely add a special fragment syntax to JSX that
doesn’t require keys.
You can use:
render(){
return (
<React.Fragment>
<div>Some data</div>
<div>Som other data</div>
</React.Fragment>
)
}
For further details refer to this documentation.
Use [], instead of ()'s to wrap the entire return.
render: function() {
return[
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
]
}
I created a component to wrap child components without a DIV. It's called a shadow wrapper: https://www.npmjs.com/package/react-shadow-wrapper
This is still required, BUT React now make sure to create elements without creating an additional DOM element.
The extra wrapping needed (normally with a parent div) because Reacts createElement method require a type parameter which is either a tag name string (such as 'div' or 'span'), a React component type (a class or a function). But this was before they introduce React Fragment.
Refer this NEW api doc for createElement
React.createElement : Create and return a new React element of the given type. The type argument can be either a tag name string (such as 'div' or 'span'), a React component type (a class or a function), or a React fragment type.
here is the official example, Refer React.Fragment.
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
</React.Fragment>
);
}
I know this question has been answered, you can of course use React.Fragment which doesn't create a node but let's you group stuff like a div.
Additionally if you want to have fun you can implement (and learn lots of things) a React mode that removes the extra div's and for this I really want to share a great video on how you can do it on the react code base itself.
https://www.youtube.com/watch?v=aS41Y_eyNrU
This is of course not something that you would do in practice but it's a good learning opportunity.
You won't be able to get rid of that div element. React.render() needs to return one valid DOM node.
Here is one way to render "transculent" components:
import React from 'react'
const Show = (props) => {
if (props.if || false) {
return (<React.Fragment>{props.children}</React.Fragment>)
}
return '';
};
----
<Show if={yomama.so.biq}>
<img src="https://yomama.so.biq">
<h3>Yoamama</h3>
<Show>
There is workaround too. The below block code generates fragment without the need of React.Fragment.
return [1,2,3].map(i=>{
if(i===1) return <div key={i}>First item</div>
if(i===2) return <div key={i}>Second item</div>
return <div key={i}>Third item</div>
})

Categories

Resources