I got it with Amire's answer
I have an array in store:
[
{
id: 1,
value: 'value 1',
},
]
In parent, I call it from store
And then, I transmit data to Child:
function Parent({array}){
return
<Child
key={array}
items={array}
/>
}
When I update array, delete
or add
item, then I get
data again from backend to update, the prop in Child will be update.
E.g:
[
{
id: 1,
value: 'value 1',
},
{
id: 2,
value: 'value 2',
},
]
But if I update
:
[
{
id: 1,
value: 'value 1',
},
{
id: 2,
value: 'value update',
},
]
prop in parent is updated, but in child is not.
My ENG is not good but I wish that everyone will understand clearly my main idea.
CodePudding user response:
Reference to your array isn't changing, so React is doing a shallow comparison and decide that it doesn't need to re-render. Either implement shouldComponentUpdate
logic yourself to explicitly check the elements of the array too, or just create a new array with the elements that you want and pass that to the component.
CodePudding user response:
As react doc says,
A “key” is a special string attribute you need to include when creating lists of elements.
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.
When you pass an array as a string representation to component key, (it most probably) gets converted to a string. meaning it will call the .toString
method.
Let's see what Array.prototype.toString
method do with your given array
const state = [
{ id: 1, value: 'value 1' },
{ id: 2, value: 'value 2' },
]
state.toString() // '[object Object],[object Object]'
const newState = [
{ id: 1, value: 'value 1' },
{ id: 5, value: 'value 5 ⭐' },
]
newState.toString() // '[object Object],[object Object]'
JSON.stingify(newState) // '[{"id":1,"value":"value 1"},{"id":5,"value":"value 5 ⭐"}]'
As you see your object will be converted to '[object Object]'
and get joined by ,
. this makes it clear why adding and deleting make triggers render but changing doesn't.
The better way to achieve this is to generate a deterministic hash to make it crystal clear for the react that mutation (changing) must trigger render. I provide a bunch of examples and you can pick what fits you.
// if id will change in your patches
key={array.map(item => item.id).join('-')}
// if id won't changes but title gets updated
// This is the probably the same as JSON.stringify
key={array.map(item => item.id item.title).join('-')}
// this example is not recommended but give you more insight
// I used combination of index and item id
key={array.map((item, idx) => `${idx}.${item.id}`).join(' ')}
// if your only the title changes this will not cause re-render
in-depth explanation on the negative impacts of using an index as a key.
If I suppose to do this I would probably remove the extra child layer and map over data directly in jsx.
function Parent({array}){
return array && array.map(item => (
<InnerChildComponent
key={'get proper key from above list fit your case based on item'}
items={item}
/>
)
}