Prevent all children re-rendering every call of setState
When rendering a long list of elements in a table for example, then any call to setState
regardless of whether it changes the data the table uses for enumeration results in a re-render of every child object.
Every check/uncheck will re-render every element. This causes major slowdown with 2000 elements that are more complex. I will use virtualization, but want to make sure this is as performant as possible before doing so.
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
const rows = Array.from({ length: 200 }, (v, k) => k + 1).map(i => ({
id: i,
field1: "hello",
field2: "cruel",
field3: "world"
}));
this.state = {
selectedIds: ,
rows
};
}
onChange(e) {
const name = e.target.name;
const checked = e.target.checked;
const selectedIds = [...this.state.selectedIds];
if (!checked) {
const index = selectedIds.findIndex(x => x === name);
selectedIds.splice(index, 1);
} else {
selectedIds.push(name);
}
this.setState(state => ({ selectedIds }));
}
render() {
const { rows, selectedIds } = this.state;
return (
<div className="App">
<h5>{selectedIds.length} Rows Selected</h5>
<table>
<thead>
<tr>
<td>Select</td>
</tr>
<tr>
<td>Field 1</td>
</tr>
<tr>
<td>Field 2</td>
</tr>
<tr>
<td>Field 3</td>
</tr>
</thead>
<tbody>
{rows.map(row => {
console.log(row);
return (
<tr key={row.id}>
<td>
<input
type="checkbox"
onChange={this.onChange}
name={row.id}
/>
</td>
<td>
<div>{row.field1}</div>
</td>
<td>
<div>{row.field2}</div>
</td>
<td>
<div>{row.field3}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
I see from other answers that it is the expected behaviour to re-run the render
function
ReactJS - Does render get called any time "setState" is called?
But if so, when the number of elements is increased to say 4000 in that link, why is there so much slowdown when clicking? Significant slowdown is noticed when only using 200 items when using slightly more complex custom React Components.
reactjs
add a comment |
When rendering a long list of elements in a table for example, then any call to setState
regardless of whether it changes the data the table uses for enumeration results in a re-render of every child object.
Every check/uncheck will re-render every element. This causes major slowdown with 2000 elements that are more complex. I will use virtualization, but want to make sure this is as performant as possible before doing so.
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
const rows = Array.from({ length: 200 }, (v, k) => k + 1).map(i => ({
id: i,
field1: "hello",
field2: "cruel",
field3: "world"
}));
this.state = {
selectedIds: ,
rows
};
}
onChange(e) {
const name = e.target.name;
const checked = e.target.checked;
const selectedIds = [...this.state.selectedIds];
if (!checked) {
const index = selectedIds.findIndex(x => x === name);
selectedIds.splice(index, 1);
} else {
selectedIds.push(name);
}
this.setState(state => ({ selectedIds }));
}
render() {
const { rows, selectedIds } = this.state;
return (
<div className="App">
<h5>{selectedIds.length} Rows Selected</h5>
<table>
<thead>
<tr>
<td>Select</td>
</tr>
<tr>
<td>Field 1</td>
</tr>
<tr>
<td>Field 2</td>
</tr>
<tr>
<td>Field 3</td>
</tr>
</thead>
<tbody>
{rows.map(row => {
console.log(row);
return (
<tr key={row.id}>
<td>
<input
type="checkbox"
onChange={this.onChange}
name={row.id}
/>
</td>
<td>
<div>{row.field1}</div>
</td>
<td>
<div>{row.field2}</div>
</td>
<td>
<div>{row.field3}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
I see from other answers that it is the expected behaviour to re-run the render
function
ReactJS - Does render get called any time "setState" is called?
But if so, when the number of elements is increased to say 4000 in that link, why is there so much slowdown when clicking? Significant slowdown is noticed when only using 200 items when using slightly more complex custom React Components.
reactjs
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within theRowItem
component to signal to React that it may not need to be re-rendered based on whatever props. AlsoPureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.
– Alexander Staroselsky
Nov 19 at 23:02
add a comment |
When rendering a long list of elements in a table for example, then any call to setState
regardless of whether it changes the data the table uses for enumeration results in a re-render of every child object.
Every check/uncheck will re-render every element. This causes major slowdown with 2000 elements that are more complex. I will use virtualization, but want to make sure this is as performant as possible before doing so.
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
const rows = Array.from({ length: 200 }, (v, k) => k + 1).map(i => ({
id: i,
field1: "hello",
field2: "cruel",
field3: "world"
}));
this.state = {
selectedIds: ,
rows
};
}
onChange(e) {
const name = e.target.name;
const checked = e.target.checked;
const selectedIds = [...this.state.selectedIds];
if (!checked) {
const index = selectedIds.findIndex(x => x === name);
selectedIds.splice(index, 1);
} else {
selectedIds.push(name);
}
this.setState(state => ({ selectedIds }));
}
render() {
const { rows, selectedIds } = this.state;
return (
<div className="App">
<h5>{selectedIds.length} Rows Selected</h5>
<table>
<thead>
<tr>
<td>Select</td>
</tr>
<tr>
<td>Field 1</td>
</tr>
<tr>
<td>Field 2</td>
</tr>
<tr>
<td>Field 3</td>
</tr>
</thead>
<tbody>
{rows.map(row => {
console.log(row);
return (
<tr key={row.id}>
<td>
<input
type="checkbox"
onChange={this.onChange}
name={row.id}
/>
</td>
<td>
<div>{row.field1}</div>
</td>
<td>
<div>{row.field2}</div>
</td>
<td>
<div>{row.field3}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
I see from other answers that it is the expected behaviour to re-run the render
function
ReactJS - Does render get called any time "setState" is called?
But if so, when the number of elements is increased to say 4000 in that link, why is there so much slowdown when clicking? Significant slowdown is noticed when only using 200 items when using slightly more complex custom React Components.
reactjs
When rendering a long list of elements in a table for example, then any call to setState
regardless of whether it changes the data the table uses for enumeration results in a re-render of every child object.
Every check/uncheck will re-render every element. This causes major slowdown with 2000 elements that are more complex. I will use virtualization, but want to make sure this is as performant as possible before doing so.
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
const rows = Array.from({ length: 200 }, (v, k) => k + 1).map(i => ({
id: i,
field1: "hello",
field2: "cruel",
field3: "world"
}));
this.state = {
selectedIds: ,
rows
};
}
onChange(e) {
const name = e.target.name;
const checked = e.target.checked;
const selectedIds = [...this.state.selectedIds];
if (!checked) {
const index = selectedIds.findIndex(x => x === name);
selectedIds.splice(index, 1);
} else {
selectedIds.push(name);
}
this.setState(state => ({ selectedIds }));
}
render() {
const { rows, selectedIds } = this.state;
return (
<div className="App">
<h5>{selectedIds.length} Rows Selected</h5>
<table>
<thead>
<tr>
<td>Select</td>
</tr>
<tr>
<td>Field 1</td>
</tr>
<tr>
<td>Field 2</td>
</tr>
<tr>
<td>Field 3</td>
</tr>
</thead>
<tbody>
{rows.map(row => {
console.log(row);
return (
<tr key={row.id}>
<td>
<input
type="checkbox"
onChange={this.onChange}
name={row.id}
/>
</td>
<td>
<div>{row.field1}</div>
</td>
<td>
<div>{row.field2}</div>
</td>
<td>
<div>{row.field3}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
I see from other answers that it is the expected behaviour to re-run the render
function
ReactJS - Does render get called any time "setState" is called?
But if so, when the number of elements is increased to say 4000 in that link, why is there so much slowdown when clicking? Significant slowdown is noticed when only using 200 items when using slightly more complex custom React Components.
reactjs
reactjs
edited Nov 19 at 23:46
asked Nov 19 at 22:35
tic
1,104821
1,104821
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within theRowItem
component to signal to React that it may not need to be re-rendered based on whatever props. AlsoPureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.
– Alexander Staroselsky
Nov 19 at 23:02
add a comment |
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within theRowItem
component to signal to React that it may not need to be re-rendered based on whatever props. AlsoPureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.
– Alexander Staroselsky
Nov 19 at 23:02
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within the
RowItem
component to signal to React that it may not need to be re-rendered based on whatever props. Also PureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.– Alexander Staroselsky
Nov 19 at 23:02
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within the
RowItem
component to signal to React that it may not need to be re-rendered based on whatever props. Also PureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.– Alexander Staroselsky
Nov 19 at 23:02
add a comment |
1 Answer
1
active
oldest
votes
To solve this issue you'll want to create an additional component for the row item. This way it will have a separate render function and not rerender itself because the row component hasn't changed, only the table component.
{rows.map(row => {
return (
<RowItem row={row} onChange={this.onChange}>
);
}}
and your new component will look something like this:
class RowItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<tr key={this.props.row.id}>
<td>
<input
type="checkbox"
onChange={this.props.onChange}
name={this.props.row.id}
/>
</td>
<td>
<div>{this.props.row.field1}</div>
</td>
<td>
<div>{this.props.row.field2}</div>
</td>
<td>
<div>{this.props.row.field3}</div>
</td>
</tr>
);
}
}
2
I think you'll want RowItem to extendReact.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.
– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383635%2fprevent-all-children-re-rendering-every-call-of-setstate%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
To solve this issue you'll want to create an additional component for the row item. This way it will have a separate render function and not rerender itself because the row component hasn't changed, only the table component.
{rows.map(row => {
return (
<RowItem row={row} onChange={this.onChange}>
);
}}
and your new component will look something like this:
class RowItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<tr key={this.props.row.id}>
<td>
<input
type="checkbox"
onChange={this.props.onChange}
name={this.props.row.id}
/>
</td>
<td>
<div>{this.props.row.field1}</div>
</td>
<td>
<div>{this.props.row.field2}</div>
</td>
<td>
<div>{this.props.row.field3}</div>
</td>
</tr>
);
}
}
2
I think you'll want RowItem to extendReact.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.
– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
add a comment |
To solve this issue you'll want to create an additional component for the row item. This way it will have a separate render function and not rerender itself because the row component hasn't changed, only the table component.
{rows.map(row => {
return (
<RowItem row={row} onChange={this.onChange}>
);
}}
and your new component will look something like this:
class RowItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<tr key={this.props.row.id}>
<td>
<input
type="checkbox"
onChange={this.props.onChange}
name={this.props.row.id}
/>
</td>
<td>
<div>{this.props.row.field1}</div>
</td>
<td>
<div>{this.props.row.field2}</div>
</td>
<td>
<div>{this.props.row.field3}</div>
</td>
</tr>
);
}
}
2
I think you'll want RowItem to extendReact.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.
– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
add a comment |
To solve this issue you'll want to create an additional component for the row item. This way it will have a separate render function and not rerender itself because the row component hasn't changed, only the table component.
{rows.map(row => {
return (
<RowItem row={row} onChange={this.onChange}>
);
}}
and your new component will look something like this:
class RowItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<tr key={this.props.row.id}>
<td>
<input
type="checkbox"
onChange={this.props.onChange}
name={this.props.row.id}
/>
</td>
<td>
<div>{this.props.row.field1}</div>
</td>
<td>
<div>{this.props.row.field2}</div>
</td>
<td>
<div>{this.props.row.field3}</div>
</td>
</tr>
);
}
}
To solve this issue you'll want to create an additional component for the row item. This way it will have a separate render function and not rerender itself because the row component hasn't changed, only the table component.
{rows.map(row => {
return (
<RowItem row={row} onChange={this.onChange}>
);
}}
and your new component will look something like this:
class RowItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<tr key={this.props.row.id}>
<td>
<input
type="checkbox"
onChange={this.props.onChange}
name={this.props.row.id}
/>
</td>
<td>
<div>{this.props.row.field1}</div>
</td>
<td>
<div>{this.props.row.field2}</div>
</td>
<td>
<div>{this.props.row.field3}</div>
</td>
</tr>
);
}
}
answered Nov 19 at 22:59
Shawn Andrews
945616
945616
2
I think you'll want RowItem to extendReact.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.
– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
add a comment |
2
I think you'll want RowItem to extendReact.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.
– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
2
2
I think you'll want RowItem to extend
React.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.– Ryan C
Nov 19 at 23:04
I think you'll want RowItem to extend
React.PureComponent
so that it will only try to render if its props change. Without this, it still won't update the DOM unnecessarily (since it will detect that the rendered result is the same), but it will still execute RowItem's render method (and compare to DOM) unnecessarily.– Ryan C
Nov 19 at 23:04
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
I agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
– Shawn Andrews
Nov 21 at 5:27
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383635%2fprevent-all-children-re-rendering-every-call-of-setstate%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Taking @ShawnAndrews answer one step farther, you should possibly consider shouldComponentUpdate within the
RowItem
component to signal to React that it may not need to be re-rendered based on whatever props. AlsoPureComponent
could help. Also, this is what libraries like recompose and Redux, depending on structure, can help with as well.– Alexander Staroselsky
Nov 19 at 23:02