Reputation: 1340
I have a child component StartExam
where I am sending two functions as props, from the parent component. I saw that it keeps rerendering because it gets new values of functions the whole time. I have used this piece of code to find out which props are being updated, and it gave me the two functions that I am sending.
componentDidUpdate(prevProps, prevState, snapshot) {
Object.entries(this.props).forEach(([key, val]) =>
prevProps[key] !== val && console.log(`Prop '${key}' changed`)
);
if (this.state) {
Object.entries(this.state).forEach(([key, val]) =>
prevState[key] !== val && console.log(`State '${key}' changed`)
);
}
}
This is how I am sending functions from the parent component:
<Route path={`${matchedPath}/start`}
render={
this.examStatusGuard(
'NOT_STARTED',
(props) =>
<StartExam
language={this.state.language}
startExam={() => this.startExam()}
logAction={(action) => this.logAction({action})}/>)
}
/>
and this is the examStatusGuard
function:
examStatusGuard(requiredState, renderFunc) {
return (props) => {
if (this.state.exam.status !== requiredState) {
return <Redirect to={this.examStatusDefaultUrl()}/>
}
return renderFunc(props);
}
}
And this are the two functions I am sending down as props:
logAction(actionModel) {
const wholeActionModel = {
language: this.state.language,
taskId: null,
answerId: null,
...actionModel
};
console.log(wholeActionModel);
return wholeActionModel;
}
startExam() {
this.logAction({action: actions.EXAM_STARTET});
this.examGateway.startExam()
.then(() => this.loadExam())
.then(() => {
this.props.history.push("/exam/task/0");
this.logAction({action: actions.TASK_OPEN, taskId: this.state.exam.tasks[0].id});
});
};
The reason I don't want the functions to be recreated is that in the child component I have a method that calls logAction
, and it is being called the whole time, instead of just once.
This is the method:
renderFirstPage() {
this.props.logAction(actions.INFOSIDE_OPEN);
return <FirstPage examInfo={this.props.eksamensInfo}>
{this.gotoNextPageComponent()}
</FirstPage>
}
I have tried with sending the functions like it is suggested in the answer, but with binding this
to them:
<StartExam
language={this.state.language}
startExam={this.startExam.bind(this)}
logAction={this.logAction.bind(this)}/>
But, the functions were being recreated again the whole time. How can I fix this?
Upvotes: 0
Views: 414
Reputation: 2254
When you send a function like you are, you are creating an anonymous function that is re-created each time the parent component renders:
startExam={() => this.startExam()}
That's an anonymous function, whose whole purpose in life is to call the actual function startExam
. It's being defined right here in the render function of the parent, so it's re-created each time. You can alternatively just send that function down itself, i.e.
startExam={this.startExam}
In this case the prop now references a stable function that is not getting recreated every time. I imagine that will fix your problem.
However, it's not entirely clear to me why it matters that the function is being recreated every time and your child component is re-rendering. The props aren't changing an infinite amount of time, but rather only when the parent is rerendering. That's usually not a problem, unless you are basing some other action to see if the previous props have changed (like with lodash, _.isEqual(prevProps,this.props)
).
Upvotes: 1