this.Setstate is not working correctly in reactJS - reactjs

I'm new to the react.
I have this state :
state = {
isLoading: true,
};
And I have this lifecycle function
componentDidMount() {
const { setPageCount, receiveApiData } = this.props.actions;
const { isLoading } = this.state;
const getData = () => {
this.setState({ isLoading: !isLoading });
receiveApiData();
setPageCount();
};
setInterval(() => {
getData();
}, 30000);
}
Here is what I'm trying to return in render():
return isLoading ? (
<Loading></Loading>
) : ( `Some Code here`)
The problem is state is Always true and my lifecycle method is not changing it to the false so my app can not render the false condition.
I don't know what to do,any suggestions please?
Everything else in getData() is working correctly

The issue is here:
this.setState({ isLoading: !isLoading });
because isLoading what you are destructuring taking previous value i.e it is not taking latest state value so its not updating your isLoading . What you need to do is this:
this.setState({ isLoading: !this.state.isLoading });
Here is the demo: https://codesandbox.io/s/interesting-chandrasekhar-pluv7?file=/src/App.js:312-332

Since your new state depends on the value of your old state, you should use the functional form of setState
this.setState(prevState => ({
isLoading: !prevState.isLoading
}));
Official documentation: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

Related

setState a props from Parent component

I'm having a lot of trouble to close my Modal component once my request is done.
My method togglePop works fine with the handleClick method i have in my modal component(I did not included here).
What i m trying to do is to reverse the "Togglepop" method into the state of Modal.js. Then, setState in my axios sbmit.
Avaibaliities.js
this.state = {
showModal: false
};
}
validation = () => {
if (this.state.showDate) {
this.setState({
showModal: true
});
}
togglePop = () => {
this.setState(prevState => ({
showModal: !prevState.showModal
}));
};
render() {
{this.state.showModal && <Modal dateModal={this.state.date} toggle={this.togglePop} />} }
Modal.js
state = {
mailFilled: '',
sent: false,
showPopup: false,
closeModal: !this.props.toggle
};
handleSubmit = (event) => {
let data = {
mailFilled: this.state.mailFilled,
dateIn: dateFirst,
dateOut: dateSecond
};
axios
{
this.setState(
{
sent: true,
showPopup: true
}
)
setTimeout(() => {
this.setState({
showPopup: false
})
}, 3000);
this.setState({
showPopup: false,
closeModal: this.props.toggle
})
This is kinda new for me. I really want to understand what im a doing wrong.
Thanks in advance
Since it's a function, I think it needs to be invoked and not just referenced
this.setState({
showPopup: false,
closeModal: this.props.toggle()
});

Cannot read property 'map' of undefined on useEffect hook

I recently started learning react and I got stuck in the above-mentioned error. I know there are plenty of answers to this error. yes, I have seen those solutions but I am not able to map those solutions to my problems. I am pasting my code below please tell me what is wrong with the below code. any help is very much appreciated. thank you.
const orders = () => {
const [stateValue, setState] = useState({
orders: [],
loading: true
});
// getting the orders
useEffect(() => {
axiosInstance.get('/orders.json').then(res => {
transformData(res);
setState({loading: false});
}).catch(err => {
console.log(err)
setState({loading: false});
})
}, []);
// transforming firebase response(objects of objects) into array of objects
const transformData = (response) => {
const ordersData = [];
if(response.data) {
for (let key in response.data) {
ordersData.push({
...response.data[key],
id: key
})
}
}
setState({orders: ordersData});
}
let orders;
orders = stateValue.orders.map((order) => <Order //error line
key={order.id}
ingredients={order.ingredients}
email={order.email}
price={order.price}
/>);
if(stateValue.loading) {
orders = <Loading />
}
return(
<div>
{orders}
</div>
)
}
The setter function of useState hook DOES NOT MERGE STATE like in its class equivalent (it mentioned in the docs):
However, unlike this.setState in a class, updating a state variable always replaces it instead of merging it.
// Merge with prev state in function component
setState(prev => ({...prev, loading: false}))
// In class component, the setter merges state by default
this.setState({loading: false});

Clearing state after render

Consider this HOC I use for fetching data
function withData(Component, endpoint) {
return class extends React.Component {
state = {
result: null,
loading: false,
error: { state: false, msg: '' }
};
fetchData = async () => {
try {
this.setState({ loading: true });
const response = await axios.get(`${endpoint}/${this.props.params || ''}`);
this.setState(state => ({ result: response.data, loading: !state.loading }));
} catch (err) {
console.log('Error caugh in withData HOC', err);
this.setState({ error: true });
}
};
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (this.props.params !== prevProps.params) {
this.fetchData();
}
}
render() {
const { result, loading } = this.state;
if (loading) return <p>Loading...</p>;
if (!result) return null;
return <Component result={result} {...this.props} />;
}
};
}
You will notice I am saying if !result do not render the component. The problem is when this.props.params to this component changes, this.state.result is preserving the value of the older state. I want to reset result to null after each render, so it behaves the exact same as the initial render.
How can I achieve this?
To make it more clear, it would be great if I could do this in componentWillUnmount so that it's ready for the next Component lifecycle. However the component never unmounts.
Please note, it must be done in the HOC and not in the Component it returns.
In this case you'll want your component (rendered by the HOC) to accept a key option, which will be the params props in my case.
Usually you use those for lists, but it can be used here as well. When a key is used, if it changes instead of updating, it will make a new instance of the component. That would mean you would not need the componentDidUpdate anymore.
You can read more about the bahavior here https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

setting state after calling api in react

I have tried numerous ways to set state but for some reason, the state never gets updated.this is the JSON data that I want my state to change to
export class Provider extends Component {
state = {
posts: [],
profileinfo: {},
dispatch: action => this.setState(state => reducer(state, action))
};
componentDidMount() {
fetch("http://localhost:3001/login").then(response =>
response
.json()
.then(data => this.setState({ profileinfo: data.firstname }))
);
console.log(this.state.profileinfo);
}
render() {
// ...
}
}
setState is asynchronous. Your console log probably triggers before the state got updated. If you want to see the result after the setState call, do it this way:
data => this.setState({ profileinfo: data.firstname }, () => {
console.log(this.state);
});

React error with not fetched data. Ugly Code and null pointer. What to do?

I have an React code that needs to fetch some data from an API, put it on a redux-store, and then render a List with this data. This is what Im doing
constructor(props) {
super(props);
this.state = {
isLoading: false,
};
}
componentDidMount() {
this.setState({ isLoading: true });
this.loadData();
}
loadData = async () => {
try {
API.getList()
.then(data => {
this.updateState(data);
})
.then(data => this.setState({ isLoading: false }))
.catch(function(error) {
console.log(error.message);
});
} catch (e) {}
};
updateState = async (data) => {
if (data != null) {
await this.props.mainActions.receiveData(data);
}
};
render() {
const { isLoading } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
let items = [];
if (this.props.items.data !== undefined) {
items = this.props.items.data.stadiums;
}
return <MyList items={items} />;
}
}
The problem is, the first time it renders, when I try to get "this.props.items" it is undefined yet.
So I need to put this ugly IF to dont break my code.
What will be a more elegant solution for this problem?
I am assuming the use of ES6 here:
I would set a defaultProp for items in the MyList component
export class MyList extends Component {
...
static defaultProps = {
items: []
}
...
}
This way, if you pass items as undefined and mapping over items in your render method it will produce an empty array which is valid jsx
Ok. Just change the "componentDidMount" with "componentWillMount".
Jsx doesn't render undefined or null so you can include your condition in your return statement.
Instead of writing an if statement, do this:
return (
{
this.props.items.data &&
this.props.items.data.stadiums &&
<Mylist
items={this.props.items.data.stadiums}
/>
}
);

Resources