Prevent all children re-rendering every call of setState












2














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.










share|improve this question
























  • 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


















2














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.










share|improve this question
























  • 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
















2












2








2


1





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.










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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


















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














1 Answer
1






active

oldest

votes


















1














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>
);
}
}





share|improve this answer

















  • 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 agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
    – Shawn Andrews
    Nov 21 at 5:27











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
});


}
});














draft saved

draft discarded


















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









1














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>
);
}
}





share|improve this answer

















  • 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 agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
    – Shawn Andrews
    Nov 21 at 5:27
















1














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>
);
}
}





share|improve this answer

















  • 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 agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
    – Shawn Andrews
    Nov 21 at 5:27














1












1








1






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>
);
}
}





share|improve this answer












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>
);
}
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 19 at 22:59









Shawn Andrews

945616




945616








  • 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 agree with Ryan, simply change React.Component -> React.PureComponent to ensure your against needless re-rendering
    – Shawn Andrews
    Nov 21 at 5:27














  • 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 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

"Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

Alcedinidae

RAC Tourist Trophy