Update App state based on Child component - reactjs

I need to update the state of a Parent component (App.js) when updating the state of a Child component where I do a GET request in componentDidMount().
I tried to pass the function setPoints as a prop but unfortunately this doesn't work.
Here's what I tried :
Child component :
class Child extends Component {
state = {
points: null
}
async componentDidMount() {
try {
const res = await axios.get(url);
const data = res.data;
this.setState({
points: data.points,
})
this.props.setPoints();
} catch (err) {
console.log('child', err);
}
}
render() {
return (
<div>
</div>
);
}
}
Parent component (App):
class App extends Component {
state = {
points: '',
}
setPoints() {
this.setState({
...this.state,
points: this.state.points
});
}
shouldComponentUpdate(nextState) {
if (this.state.points !== nextState.points) {
return true;
}
return false;
}
render() {
return (
<div className="App">
<Route exact path="/child" render={() => <Child setPoints={this.setPoints} />} />
</div>
);
}
}
Can anyone please help me with this? Help would be highly appreciated.
EDIT
I tried what Joe Clay wrote and this makes perfect sense, but I still catch an error. Here's my updated code :
async componentDidMount() {
try {
const res = await axios.get(url);
const data = res.data;
console.log(data.points);
this.props.setPoints(data.points);
} catch (err) {
console.log('child', err);
}
It does log the value of points, but for some reason I get : "Cannot read property 'points' of undefined".

Consider the value of data in Parent Component.I would be changing the value of data by passing a prop to a function which does a setState in the parent and thereby changing the value to the desired value.
ParentComponent
class Parent extends React.Component{
constructor(props){
super(props);
this.state({
name:''
})
}
handleChange(value){
this.setState({name:value});
}
render(){
return (<Child handleChange={this.handleChange} />)
}
}
Pass the handleChange function as a prop to the child component.
Child component
export default class Child extends React.Component{
sendData(false){
this.props.handleChange(hello) //make sure to pass the value in the
argument that you wish to do a setState on in the parent component
}
}
this would set the value of name to hello in the parent component.

on child:
this.props.setPoints(data.points)
on parent:
setPoints(points) {
this.setState({
...this.state,
points
});
}

Related

Unable to pass data from a Parent'state to a Child's state in React

I am trying to pass an Array of values from a Parent module to a Child module, and set them in the Child's state in order to display a chart.
Here is my Parent module:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
this.getRates();
}
getRates = () => {
fetch(
"https://api.exchangerate.host/timeseries?start_date=2022-07-01&end_date=2022-07-05&base=USD&symbols=EUR"
)
.then((res) => res.json())
.then((timeseries) => {
const rates = Object.values(timeseries.rates);
this.setState({
data: rates,
});
});
};
render() {
const data = this.state;
return (
<>
<Child data={data} />
</>
);
}
}
And here is the Child module:
class Child extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
};
}
componentDidMount() {
this.setState({
items: this.props.data,
});
}
render() {
const { items } = this.state;
console.log("Child data from state: ", items);
console.log("Child data from props: ", this.props.data);
return (
<>
<ReactApexChart options={items} />
</>
);
}
}
Here is what I am getting from the console.log():
Child data from state: []
Child data from props: (30) [95.9182, 95.7676, 94.8036, ..., 95.2308, 95.2906]
Why am I unable to set the Child's state with this data?
Your Child component does not get its state updated because the lifecycle function you are using does not get called when the component gets an updated set of props from the Parent.
Please check the Updating heading on https://www.w3schools.com/react/react_lifecycle.asp
You will not find the componentDidMount lifecycle in there because it does not get called on a prop update.
What you need to use is something like getDerivedStateFromProps
static getDerivedStateFromProps(props) {
return {items: props.data};
}
This makes sure that every time the Parent sends an updated value in the props, the Child uses it to update the state and then re-render accordingly.

Overwriting state when loaded from props

I have this code, or the relevant parts at least....
class ClubDetails extends React.Component {
constructor(props) {
super(props)
this.state = {
clubBetsPending: this.props.pendingBets,
}
this.updatePbd = this.updatePbd.bind(this)
}
static async getInitialProps({ query }) {
const props = axios
.post('http://localhost:3000/api/club', { clubId: query.clubid })
.then((res) => {
//pass response to UI
if (res.data.response.boolean) {
return {
pendingBets: res.data.payload,
}
}
})
.catch((e) => {
//Not Found
})
return props
}
updatePbd(newBet) {
var newPbd = [newBet[0]].concat(this.state.clubBetsPending)
this.setState({ clubBetsPending: newPbd })
}
render() {
return ( <>
<NewBet updatePbd={this.updatePbd} />
<PendingBets data={this.state.clubBetsPending} />
</>
)
}
From what I have read my render isn't running when it hits the setState in updatePbd because the state is being recieved from the props this.props.pendingBets. So I understand the problem, i just don't understand what the solution is?
Can someone help, I can't find anything for this problem or I don't know what to search for.
Thanks

Error: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application

I'm getting the above error and I don't know how to handle it.
I got a component. And in the render() i'm looping through an array and placing another component and parsing a value to that component like this:
render() {
let allProducts = this.state.products.map((product, i) => {
return (
<div key={product.article}>
...
<PriceStock value={product.article} />
...
</div>
)
})
}
In the PriceStock component i'm fetching some data with axios like the code below:
export default class PriceStock extends React.Component {
constructor(props) {
super(props);
this.state = ({
buttoprice: ''
})
this.getPriceAndStock = this.getPriceAndStock.bind(this)
}
getPriceAndStock(articleNo) {
return axios.post('LINK_TO_URL', {
articleNo: articleNo
}).then(result => {
return result.data
})
}
async componentDidMount() {
let pricestock;
pricestock = await this.getPriceAndStock(this.props.value)
let bruttoPrice = PRICE_TO_PARSE_TO_THE_STATE;
this.setState({ buttoprice: bruttoPrice })
}
render() {
return (
<div >
{this.state.buttoprice}
</div>
);
}
}
The error seems to happen when I try to setState in the componentDidMount, any suggestions?
this is an error occurs because you are updating state before it gets initialized
perform your loading activities in the constructor it is the right way to do it
getPriceAndStock(orderNumber, articleNo) {
return axios.post('LINK_TO_URL', {
orderNr: orderNumber, vareNr: articleNo
}).then(result => {
return result.data
})
}
constructor() {
this.getPriceAndStock(this.props.value)
.then(pricestock=>{
let bruttoPrice = PRICE_TO_PARSE_TO_THE_STATE;
this.state({ buttoprice: bruttoPrice })
})
.catch(console.log)
}
Found the answear in this question: https://github.com/material-components/material-components-web-react/issues/434
It's remindend me a little bit about the comment with another stackoverflow question.

React Native Pass Parent Method to Child Component

I am trying to pass method from my parent component to child component. My code is correct i think but still it shows the error undefined is not an object(evaluating '_this2.props.updateData') . I don't know whats the issue because i searched the internet a lot and everyone is passing props to child like this. Kindly tell what am i missing
Parent:
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
// data should be 'child data' when the
// Test button in the child component is clicked
}
render() {
return (
<Child updateData={val => this.updateData(val)} />
);
}
Child:
class Child extends React.Component {
const passedData = 'child data'
handleClick = () => {
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick()}>Test</button>
);
}
}
`class Child extends React.Component {
handleClick = () => {
const passedData = 'child data'
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick}>Test</button>
);
}
}`
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
}
render() {
return (
<Child updateData={this.updateData} />
);
}
}
and child component: `
class Child extends React.Component {
const passedData = 'child data'
handleClick = () => {
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick}>Test</button>
);
}
}
`
You need to pass the function directly, not as a callback
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
// data should be 'child data' when the
// Test button in the child component is clicked
}
render() {
return (
<Child updateData={this.updateData} />
);
}
I think you need to pass a function like this. Check out this solution.

How to force children rerendering after axios call in React?

I'm working on a form with interactive inputs. They have to actualise themselves with information into parent state.
I use Axios to get the data to show, getting them from an external API. I tried to set default values, but they never actualise with newer values.
class Form extends React.Component {
getData() {
axios.get('http://xxx/getform/').then(
res => this.setState(res.data)
);
}
componentDidMount() {
this.getData();
setInterval(() => {
this.getData();
}, 36000000)
}
render() {
return (
<div>
<form>
<DatePicker />
</form>
</div>
)
}
}
class DatePicker extends React.Component {
constructor(props) {
super(props);
this.state = {
selected: new Date(),
runMin: new Date(),
runMax: new Date()
};
}
getDate() {
console.log('DAD');
try { // if axios didn't finish, to avoid undefined
this.setState({
runMin: super.state.RunMin,
runMax: super.state.RunMax})
} catch (e) {
this.setState({
runMin: new Date(),
runMax: new Date()})
}
}
componentDidMount() {
this.getDate();
this.setState({selected: this.state.runMax});
}
render() {
return (<div></div>);
}
}
Actually after axios call, the children doesn't rerender. I separated the call for axios and the component using it, because the Form component do a single call for multiple children (not displayed here), and they read the parent's state to render.
Firstly, you should not access the parents state using super and instead pass the required value as props
Secondly, componentDidMount lifecycle is executed on initial mount and hence the logic within it won't execute when the parent state updates.
The correct way to handle your case would be
class Form extends React.Component {
state = {
RunMin: new Date(),
RunMax: new Date()
}
getData() {
axios.get('http://xxx/getform/').then(
res => this.setState({RunMin: res.data.RunMin, RunMax: res.data.RunMax})
);
}
componentDidMount() {
this.getData();
setInterval(() => {
this.getData();
}, 36000000)
}
render() {
return (
<div>
<form>
<DatePicker runMin={this.state.RunMin} runMax={this.state.RunMax}/>
</form>
</div>
)
}
}
class DatePicker extends React.Component {
render() {
console.log(this.props.runMin, this.props.runMax);
return (<div></div>);
}
}
The way you are setting the state is incorrect
Change
this.setState(res.data);
To
this.setState({data: res.data});
You need to set the response to a state field you have in component and make sure you pass the data to the child component

Resources