In my React.JS app I have a function inside of a Functional Component that renders JSX that I need when the app loads initially. The catch is I don't need it re-run every time the component updates and the return()
method is called. This content is rendered with an API call and it's "expensive" to re-run constantly.
How do I limit how often this will run.
...
<Col lg="8">
<div className="tab-content" id="newForm-wrapper">
{/* !! STOP THIS FROM BEING CALLED EVERY RENDER !!! */}
{renderSectionContent(formJSON)}
</div>
</Col>
...
Below is the function being called:
const renderSectionContent = json => {
if (json.hasOwnProperty("form") && json.form.hasOwnProperty("sections")) {
return json.form.sections.map((section, i) => {
return <FormSection key={i} json={section} />;
});
} else {
return <FormSection json={{}}/>;
}
};
To prevent this function from being run every render, you will need to store return value of the function in local state. You will probably want the function to be re-run every time the json data changes, which can be difficult if the json has deeply nested data. Depending on how you are injecting the json into your component will change exactly how you will set the state.
Here is an example of how this would be done assuming the data was passed as a prop to your class component:
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
sectionContent: renderSectionContent(props.formJson),
};
}
renderSectionContent = json => {
// do stuff
return <FormSection />;
}
render() {
return (
<Col lg="8">
<div className="tab-content" id="newForm-wrapper">
{sectionContent}
</div>
</Col>
);
}
}
Or using Hooks (new starting in React version 16.8):
export default function MyComponent(props) {
const [sectionContent, setSectionContent] = useState(renderSectionContent(props.formJson));
const renderSectionContent = json => {
// do stuff
return <FormSection />;
}
return (
<Col lg="8">
<div className="tab-content" id="newForm-wrapper">
{sectionContent}
</div>
</Col>
);
}
Assuming your json input to your function is either being passed down as a prop to your component or is in state ( if it's not maybe you could store it in state? ) :
Two of some of the options you could use here are to either make that function into it's own component with returns the desired component based on the condition; this way you can pass down json as a prop and it will only run again if that prop changes. Or you could use createSelector
from the react reselect library where you hold your json in state (or you can replace state with props in the example below ) and you pass in your state or prop to your function (which will now be a reselect function). This way your function will only run again if your json in state or props changes
Example
import { createSelector } from 'reselect'
static renderSectionContent = createSelector(
(state) => state.json,
(json) => {
if (json.hasOwnProperty("form") &&
json.form.hasOwnProperty("sections")) {
return json.form.sections.map((section, i) => {
return <FormSection key={i} json={section} />;
});
} else {
return <FormSection json={{}}/>;
}
}
)
render() {
let selectionContent = this.renderSectionContent(this.state)
..
<Col lg="8">
<div className="tab-content" id="newForm-wrapper">
{selectionContent}
</div>
</Col>
...
}
every time createSelector is called, it will return the previous computed return from the function, unless one of the inputs to the createSelector function change
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With