React list with no keys - javascript

I have an array of number that I wish to render in a tabular form. The array is returned from an API call, not generated by my app.
The data may change but is unlikely to do so, and in any case there are only twenty odd values, so re-rendering the whole table is not really a problem.
A simple data.map(value => <td>{value}</td> should do it.
But I keep getting an Each child in an array or iterator should have a unique "key" prop. warning. Is there any way that I can tell React that there is no key and that I wish it to re-render the whole table if anything changes.
Alternatively, is there any way that I can generate a unique key for each entry? The data items are not guaranteed to be unique.
I should add that I understand what keys are for and why they are useful, but in this instance I do not have any and the easiest thing would be not to use them, since there is unlikely to be a re-render.

You can use the index as the key. I think its worth reiterating that using the index as the key only works fine in the very specific scenario that the OP is facing.
This is particularly annoying when requirements change and all of sudden the list is being modified. This shows up as items not being updated during the render because the item updated has the same key (the index), its value is different, but react only cares about the key.
In cases where your data has no unique key. You should use some function that generates a unique id for each item. A simple version of that function just increments a global counter:
// Declared globally (as in attached to window object or equivalent)
var myuniqueidcounter = 0;
function uniqueId() {
myuniqueidcounter += 1
return myuniqueidcounter;
}
// Do this in the props change or whereever your data gets passed in
let keyedData = data.map(value => Object.assign(value, { Id: uniqueId() });
// In render
data.map(value => <td key={value.Id}>{value}</td>
That way, on multiple render calls, the ids returned are always unique. We assign the key when we get the data to avoid having to re-render the entire list on each call to render().
However, this case is actually pretty rare as you can usually find some combination of the backing data that will produce a unique key for each entry.
If you do go index-as-key
This article lists 3 conditions that should be met when choosing index-as-key approach that I think is a good check list:
The list and items are static–they are not computed and do not change;
The items in the list have no ids;
The list is never reordered or filtered.

data.map((value,index) =>{
<td key={index}>{value}</td>}
)
or
data.map((value,index) =>{
let i = Math.floor(Math.random() * 1000+1)
<td key={i}>{value}</td>}
)
You can use index as your key as it is unique each time

Based on the question asked, it might be worth saying that there is an another solution to this that doesn't use keys:
e.g. The following will complain about not having unique keys:
React.createElement('div', {}, [<span>1</span>, <span>2</span>]);
However, the following renders all children with no problems (This is what JSX transformed to JS looks like for nodes with multiple children):
React.createElement('div', {}, <span>1</span>, <span>2</span>);
So if you have e.g. a smallish list of generated react element fragments and unique keys don't offer and advantage in your situation, you can do:
React.createElement.apply(null, ['div', {}, ...elementList])
Notes:
elementList is passed as arguments to React.createElement which might be an issue if the list is huge.
It will re-render all the children with each render.
Using unique keys is generally the recommended approach, and is more performant for re-rendering.
However there are occasions where you just want to render in a single shot and don't care about re-rendering, or the data is not structured in a way that you can make good use of unique keys. You can use this as a work-around if you really need to.

Related

Redux best practice to filter data

in the process of developing an application, I'm facing a question about whether I'm using Redux correctly.
I have a fav:[] in which I add product objects and render their list. However, in order for the data not to be lost, I have to copy this fav:[] to favCopy:[] and only after that execute .filter
Example code:
case "fav":
state.fav = action.payload.filter === 'all'
? state.favCopy
: state.favCopy.filter((item: any) => item[type] === action.payload.filter)
break;
I would like to understand how right I am by keeping the original array intact? Maybe there is a way not to multiply arrays and use only one state?
We would recommend not doing filtering directly in the reducer most of the time. Instead, keep the original array in state as-is, and then also store a description of how you want the filtering to be done. From there, use selector functions to derive the filtered value as needed:
https://redux.js.org/usage/deriving-data-selectors

React index as key, is this a good practice? or should I use react-uuid?

Hi have a list of items that need to be rendered as a group of buttons, I just want to know which is the good and simplest solution.
first option is just use the key as item key
const sampleoutput =[];
for (const [key, value] of Object.entries(sampleItem)) {
sampleoutput.push(<li>
<a key={key}
href="#!"
onClick={value.onClick}
>
{value.title}
</a>
</li>);
}
the second solution is to use react-uuid
import uuid from "react-uuid";
sampleItem.map((value) => {
return (<li>
<a key={uuid()}
href="#!"
onClick={value.onClick}
>
{value.title}
</a>
</li>);
})
I want also to consider the performance, the second option has another set of processes to generate a key. I am a little concerned with the first option even it is much simpler because of this article https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Thank you in advance for your advice.
React expects stable static key which will last till component life
Using this key, it decide whether new component instance need to
create or have to update existing component instance property.
react-uuid will generate dynamic key whenever you make a call to uuid() and it will regenerate on every rendering.
Dynamically generated new key will cause to create a new component instance every time whenever there is re-rendering happened.
It's better to create a key from collection only which does not changes and exist there until data exist in collection.
Try to avoid react-uuid and use first approach.
My opinion, be careful when you want to use key = index, some methods can mutate your array (slice / splice), and index will be mess.
Just my opinion, bro.
I wouldnt use index as key because
reordering a list, or adding and removing items from a list can cause
issues with the component state, when indexes are used as keys. If the
key is an index, reordering an item changes it. Hence, the component
state can get mixed up and may use the old key for a different
component instance.
Therefore, avoid this practice, and make sure unique ids are generated
to be assigned as key.
So as you mentioned UUid are the best. source for unique generation of keys
hope it helps. feel free for doubts

What is the significance of keys in ReactJS?

I want to understand what happens if I don't use keys in dynamically added components. I removed keys and it renders without any issue and just gave warning messages regarding key usage. Would someone please give some example of what the consequences are if we don't use keys?
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
Example:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
TL;DR Use unique and constant keys when rendering dynamic children, or expect strange things to happen.
One of the tricky aspects I've found during the few weeks I've been using React.js is to understand the key property you're expected to pass to a component when it's part of an array of children. It's not that you have to specify this property, things will work most of the time apart from getting this warning on the console:
Each child in an array should have a unique "key" prop. Check the render method of undefined.
By reading the linked documentation it can be easy to not see the implications of this affirmation:
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
At first it looked to me it was all about performance but, as Paul O’Shannessy pointed, it's actually about identity.
The key here is to understand not everything in the DOM has a representation in React "Virtual DOM" and, because direct manipulations of the DOM (like a user changing an value or a jQuery plugin listening an element) are unnoticed by React, not using unique and constant keys will end up with React recreating the DOM node of a component when the key is not constant (and losing any untracked state in the node) or reusing a DOM node to render another component when the key is not unique (and tying its state to this other component).
Here you have a live demo showing how awful the results are:
http://jsfiddle.net/frosas/S4Dju/
Just add an item, change it, add more items and see what happens.
Also see
Source
Another useful usage of React keys other than creating dynamic elements is reseting elements when their keys change, for example in a project I had an <input/> element of type file and I wanted the element to be initialized to its initial value (no file chosen) each time the component renders, so I did the following:
Parent constructor:
this.state = {
fileInputKey: Date.now()
// other properties
};
The state object also had other properties, I just added this one for the sake of this example
Each time I wanted the input element in the child component be reset I did:
this.setState({fileInputKey: Date.now()});
Parent render:
<Child fileInputKey={this.state.fileInputKey}/>
Child render:
<input key={this.props.fileInputKey} type="file" onChange={this.onSelectFile}/>
Also see this example from React blog:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

React.js: the key value in each child component should be unique?

I use React to render a list of data, but each item in the data have not been assigned id or uuid or something like identify property. Can I use the item index as the key? like:
data.map((item, index) => {
<Item key={index}></Item>
})
What I concerned is if some other list on the page also use the order index as the child component key, would it matter? Should the key be a unique identify?
The key only needs to be unique to that list.
I also had that worry initially.
From the official docs:
Remember that the key only has to be unique among its siblings, not
globally unique.
Keys should be stable, predictable, and unique. Unstable keys (like
those produced by Math.random()) will cause many nodes to be
unnecessarily re-created, which can cause performance degradation and
lost state in child components.
Read more here: Reconciliation - Keys
You can do this if you not going to move your elements within list. Your elements will have different indices each time you move them, so react can't track which elements a moved and which just changed their data.
indices must be unique whithin their lists, they may intersect with other lists.

Can one add React Keys after instantiation?

I’m making a collection of React Elements and displaying them; what follows is a trivial example to frame the problem of how-would-one-modify-an-preexisting-instantiated-element only.
var c = [
<div>A</div>,
<div>B</div>,
// ...
<div>Z</div>
];
var ListComponents = React.createClass({
render: function() {
return <div>{c}</div>;
}
});
ReactDOM.render(<ListComponents/>, document.getElementById('root'));
While the code above “works,” it renders a console message I’d rather not ignore:
Warning: Each child in an array or iterator should have a unique "key" prop.
Check the render method of `ListComponents`.
See https://fb.me/react-warning-keys for more information.
Superficially, I could just add a unique key="…" string to each element in c and be done with it.
However, that seems a quite verbose, especially since I have the data in an indexed array and a functional language that in theory can assign each key its matching index value without manually having to enter it as a source literal.
I’d love to be able to just do this...
c.forEach( (e,i) => e.key = i ); // ...or call some setter
What’s the *right* React-way to do this -and- keep the code clean?
ADDENDUM:
...for the curious or those that want to just say add a key field...
The collection I'm using is actually an array of tuples containing meta-data and a corresponding React Element, a custom Component, or some huge JSX block. The example above overly trivializes what the actual data looks like as well as its irregularities.
As the source data itself is quite long, updated often, and not maintained by a developer; it is highly error prone to missed key fields or duplicates values from manual entry. Hence the desire to do it entirely programmatically. I can not count on the data owners to do it properly. They can't read code, so ideally I'd rather not mess up the data structures with a lot of "programming goop."
The collection is manipulated a few times, putting various runs of certain elements into other dynamically created wrappers, so that the final collection is actually generated by a few transformations, filters, and maps before it is ultimately displayed.
A major shout out to Wes Bos, who came up with a clever solution that works!
The code is a simple one liner and does exactly what I was looking for:
c = c.map( (el,key) => React.cloneElement(el, {key} ));
We're building a new collection using the .cloneElement() method, which I was unaware of. That was what I needed, it turns out.
In the .map() operation, the lambda function is passed both the element and the index. It's return value is a cloned element, but with the key property set.
By cleverly naming the index element key, it allows the short notation for the expression { "key" : key }. This object augments the cloned object.
In the end, I end up with a new collection of identical objects, each with a key property set to the index.

Categories

Resources