I have a React ponent with a prop 'total' that changes every time the ponent is updated:
function MyView(props) {
const total = props.data.loading ? 0 : props.data.total;
return (
<p> total </p>
);
}
The first time the ponent mounts the total is say 10. Every time the ponent is updated because of a prop change the total goes up.
Is there a way I can display the original total (in this example 10)?
I have tried setting it in this.total inside ponentDidMount, but props.data.total is not yet available when ponentDidMount is called. Same with the constructor. The total only bees available when props.data.loading is false.
I have a React ponent with a prop 'total' that changes every time the ponent is updated:
function MyView(props) {
const total = props.data.loading ? 0 : props.data.total;
return (
<p> total </p>
);
}
The first time the ponent mounts the total is say 10. Every time the ponent is updated because of a prop change the total goes up.
Is there a way I can display the original total (in this example 10)?
I have tried setting it in this.total inside ponentDidMount, but props.data.total is not yet available when ponentDidMount is called. Same with the constructor. The total only bees available when props.data.loading is false.
Share Improve this question asked Jun 29, 2018 at 14:46 Alina BoghiuAlina Boghiu 1031 gold badge1 silver badge6 bronze badges 1- You can render 0 if data loading or props.data.total if not – Kasabucki Alexandr Commented Jun 29, 2018 at 14:51
5 Answers
Reset to default 3In order to get access to lifecycle features, you must move from function, stateless ponent, to a class ponent.
in the below example, InitialTotal
is initialized in the construstor
lifecycle method and it never changes.
currentTotal
, is incremented each time the render function is called - when the ponent is re-rendered (because of props change or state changes)
it should look something like that:
class MyView extends React.Component {
constructor(props) {
super(props)
this.initialTotal = 10;
this.currentTotal = 10;
}
render() {
this.currentTotal+=1;
return (
<p>InitialToal: {this.initialTotal}</p>
<p>Current Total: {this.currentTotal}</p>
);
}
}
You could create a stateful ponent and store the initial total
in the ponent state.
Example
class MyView extends React.Component {
state = {
initialTotal: this.props.total
};
render() {
const { total } = this.props;
const { initialTotal } = this.state;
return (
<div>
<p> Total: {total} </p>
<p> Initial total: {initialTotal} </p>
</div>
);
}
}
class App extends React.Component {
state = {
total: 10
};
ponentDidMount() {
this.interval = setInterval(() => {
this.setState(({ total }) => {
return { total: total + 1 };
});
}, 1000);
}
ponentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <MyView total={this.state.total} />;
}
}
If I understand your requirements correctly...
function MyView(props) {
// if you only need to set the value once on load just use useState.
// the const total will be the value you pass in to useState.
const [total, setTotal] = useState(props.data.loading ? 0 : props.data.total)
// if its possible that the value is not available on initial load and
// you want to set it only once, when it bees available, you can use
// useEffect with useState
useEffect(() => {
// some condition to know if data is ready to set
if (!props.data.loading) {
setTotal(props.data.total)
}
}, [props.data.total, setTotal, props.data.loading]
// this array allows you to limit useEffect to only be called when
// one of these values change. ( when total changes in this case,
// as the const function setTotal will not change
// ( but react will fuss if its used and not in the list ).
return (
<p> {total} </p>
);
}
I have the same need. With a functional ponent, I need to store the inital snapshot of states, let user play with different state values and see their results immediately, eventually, they can just cancel and go back to the initial states. Apply the same structure to your problem, this is how it looks:
import React from 'react';
import { useEffect, useState } from "react";
const TestView = (props: { data: any }) => {
// setting default will help type issues if TS is used
const [initialTotal, setInitialTotal] = useState(props.data.total)
useEffect(() => {
// some condition to know if data is ready to set
setInitialTotal(props.data.total);
// Critical: use empty array to ensure this useEffect is called only once.
}, [])
return (
<div>
<p> { initialTotal } </p>
<p> { props.data.total } </p>
</div>
);
}
export default TestView
You can use getDerivedStateFromProps
life cycle method.
static getDerivedStateFromProps(props, state){
if(props.data.total && (props.data.total==10)){
return {
total : props.total // show total only when its 10
}
}else{
return null; // does not update state
}
}