Reputation: 784
I have a component a table with many rows (50-100). There is an ability to edit lines and type there text. All lines are stored in redux store. I update store on every keypress and it takes about 1-1.5sec before the typed character is appeared in the textarea. Every line is a separate component.
The approximate structure is bellow (but of course it's much more complex)
@connect(store => {
return {
phrases: store.phrases
};
})
export default class TableContainer extends React.Component {
handlePhraseUpdate = value => {
// update redux store here
};
render() {
return this.props.phrases.map((phrase, index) => {
return (
<Phrase
phrase={phrase}
onPhraseUpdate={this.handlePhraseUpdate}
/>
)
})
}
}
How can I refactor this code?
Upvotes: 2
Views: 796
Reputation: 13349
Most likely your performance issues are not related to redux, but to ReactJS itself.
This is because whenever you update your global object, all your rows are re-rendered. You should re-render only the row that the user is updating.
You can have control over a component render, using the shouldComponentUpdate method.
For example, you want to update the component only if its internal state has changed.
Upvotes: 1
Reputation: 6944
When dealing with large collections in Redux, it's best to factor you code so that the fewest components re-render when an item in the collection changes.
In your current implementation, when a Phrase
is updated, the TableContainer
receives a whole new array of phrases and will re-render all of them, even though only one has changed.
By connecting the Phrase
component and looking up the individual phrase for each one will result in just the single row updating when the phrase is updated.
It is best to use an id
of some kind on the values, for example:
@connect((store, ownProps) => {
return {
phrase: store.phrases[ownProps.id]
}
})
export default class Phrase extends React.Component {
handlePhraseUpdate = value => {
// update redux store here
}
render() {
const { phrase } = this.props
// render phrase
}
}
@connect(store => {
return {
// this could also be stored rather than calculated each time
phrases: store.phrases.map(p => p.id)
};
})
export default class TableContainer extends React.Component {
render() {
return this.props.phrases.map((id) => {
return (
<Phrase key={id} id={id} />
);
});
}
}
If you don't have an id
you can use the index in the array:
@connect((store, ownProps) => {
return {
phrase: store.phrases[ownProps.index]
}
})
export default class Phrase extends React.Component {
handlePhraseUpdate = value => {
// update redux store here
}
render() {
const { phrase } = this.props
// render phrase
}
}
@connect(store => {
return {
phraseCount: store.phrases.length
};
})
export default class TableContainer extends React.Component {
render() {
const phrases = []
let index = 0
for (let index = 0; index < this.props.phraseCount; index++) {
phrases.push(<Phrase key={index} index={index} />)
}
return (
<div>
{ phrases }
</div>
)
}
}
Hope this helps.
Upvotes: 2