how can I retrieve the updated state element in componentDidMount in reactjs - reactjs

I'm trying to retrieve the updated state value in componentDidMount() to append that value as a parameter in fetching data from an API. I have created this handleChange() method from where I can update the state with current required values. The problem is componentDidMount() hits before the first rendering of page so it shows me null value if I try to fetch the state value. I do not know how can I mention that I want to fetch the value after second rendering.
constructor(props) {
super(props)
this.state = {
names: [],
equipments: [],
isLoaded: false,
inputValue: null,
siteID: ''
};
}
handleChange = selectedOption => {
let { inputValue, stateID } = this.state;
this.setState({ ...this.state, inputValue: selectedOption });
console.log(`Option selected: ${selectedOption.value}`);
let selectedElement = selectedOption.value;
let filteredID = stateData.filter(name => name.name == selectedElement)
.map((name) => {
return name.id
})
// console.log(filteredID[0]);
this.setState({ stateID: filteredID[0] })
localStorage.setItem(stateID, filteredID[0]);
};
ComponentDidMount() {
const token = localStorage.getItem("token");
console.log("Inside Component Drop Down =" + token);
// let stateid = this.state.stateID;
// console.log("stateid" + stateid);
let stateid = 23301;//
let url2 = `https://applicaiton/api/helpdesk/get_personID/?stateid=${stateid}`;
fetch(url2, {
method: "GET",
headers: { "Content-Type": "application/json", "Authorization": `Token ${token}` },
credentials: "same-origin"
})
.then((results1) => {
return results1.json();
}).then(data2 => {
this.setState({
isLoaded: true,
equipments: data2,
})
});
}

Rather than componentDidMount, consider using the React lifecycle method componentDidUpdate as follows:
componentDidUpdate(prevProps, prevState, snapshot) {
// Make comparison between this.state and prevState
// as necessary to retrieve proper value
}

Related

Preact/React and setting state after fetch

My calls to setState are doing nothing in the then of a fetch.
The class is declared like this:
export default class QuestionHolder extends React.Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = {
completed: false,
revealAnswer: false,
selectedAlternative: undefined,
submitting: false,
explanation: 'philosophy',
}
console.log('props', props)
console.log('state', this.state)
}
fetch(`/questions/${this.question.id}/submit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
chosen: this.state.selectedAlternative.id,
}),
})
.then(response => response.json())
.then(data => {
console.log('data', data)
console.log('state before', this.state)
this.setState({
explanation: 'phil says so'
})
console.log('state after', this.state)
})
The fetch works fine (returns data and a 200 etc etc - this is legacy code I am updating), but the calls to console.log show that this.state never changes from the values set in the constructor.
State updates may be asynchronous and reading it immediately after setting it will not provide the correct result.
The right place to check for state change is either to pass callback as second argument to setState method
this.setState({
explanation: 'phil says so'
},() => {
console.log('Set the explanation state successfully')
})
or using componentDidUpdate lifecycle method.
componentDidUpdate(prevProps, prevState){
if (prevState.explanation !== this.state.explanation) {
console.log('Set the explanation state successfully')
}
}

This.props doesn't load data from react/redux

I have the following method:
const getAgentData = () => {
axios.get('http://localhost:3000/api/agent', {
headers: {
'Content-Type': 'application/json'
}
})
.then(async res => {
const dbData = res.data.data;
let dataForTable = dbData.map( el => {
let obj = {};
obj._id = el._id;
obj.name = el.name;
obj.phone = el.phone;
if(el.name) {obj.email = el.email}
return obj;
})
await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });
})
.then(() => {
setLoading(false)
})
.catch((error) => {
console.error(error)
})
}
I update the redux state with this line: await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });
in a child component I run this:
componentDidMount() {
console.log(this.props.photographers)
}
In the original state this.props.photographers = [];
this is what is logged to the console, it never logs the udpated redux state. From my understading redux should automatically update and it should console.log the udpated state. Any idea what I'm doing wrong?
I also tried logging data with the props being here but it's also an empty array:
class DataTableComponent extends Component {
constructor(props) {
super(props)
this.state = {
data: this.props.photographers,
loading: false,
name: '',
phone: '',
email: '',
}
}
...
My redux map to props in the child component I'm describing is:
function mapStateToProps(state) {
return {
photographers: state.Customizer.photographers
}
}
export default connect(mapStateToProps)(DataTableComponent);
Check if await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });, seems that you are not sending the payload correctly.
You can log or debug how this action payload data is coming to its reducer.

React JS - TypeError: this.state.data.map is not a function

Now i am trying to fatching data from API using axios and React JS. But when i use this code i got this error:
TypeError: this.state.countries.map is not a function
I have state data:[] and I am trying to set the values of URL in the state. So my code like this:
//get user token
const GetTokens = 'Bearer '.concat(localStorage.getItem('token'));
export default class Index extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
countries: [],
response: {}
}
}
componentDidMount() {
axios.get(apiUrl + '/country-lists', { headers: { Authorization: GetTokens } })
.then(response => response.data).then(
(result) => {
this.setState({
countries: result
});
},
(error) => {
this.setState({ error });
}
)
}
And in my render like this:
{this.state.countries.map(list => (
{list.name}
))}
Also i tried like this.
render() {
const (countries ) = this.state
const (countries = []) = this.state
In my opinion, I made no mistake while getting a token and referencing the map. But I can't figure out where I made the mistake.
By looking at your console.log I think you should use result.data
componentDidMount() {
axios.get(apiUrl + '/country-lists', { headers: { Authorization: GetTokens } })
.then(response => response.data).then(
(result) => {
this.setState({
countries: result.data
});
},
(error) => {
this.setState({ error });
}
)

Unable to reference react 'this' from fetch() callbacks inside event handler

Unable to this.setState() with fetch() response
Did fetch() inside form submit event handler, but unable to set the state from the fetch() callbacks
TypeError: Cannot read property 'setState' of undefined
...
constructor(props) {
super(props);
this.state = { deviceName: '', devices: [] };
this.handleChange = this.handleChange.bind(this);
this.handleSearchDevice = this.handleSearchDevice.bind(this);
}
componentWillMount() {
this.setState({
devices: this.props.devices
});
}
componentDidMount() {
}
componentWillReceiveProps(nextProps) {
this.setState({
devices: nextProps.devices
});
}
handleChange(event) {
this.setState({deviceName: event.target.value });
}
handleSearchDevice(event) {
console.log('Searching '+this.state.deviceName)
event.preventDefault();
//Get data from API
const url = 'device/name'
const data = { deviceName:this.state.deviceName}
fetch(url, { method: 'POST',
body: JSON.stringify(data),
headers:{ 'Content-Type': 'application/json' }
}).then(res => {
res.json().then(function(data) {
console.log('API Response: '+JSON.stringify(data))
try {
this.setState({devices: data.resp, deviceName: data.deviceName})
} catch(err) {
console.log('catch ' + err.stack)
this.callback1(data)
}
});
}).catch(error => {
console.error('Error:', error)
}).then(response => {
console.log('Success:', response)
});
}
callback1(data) {
this.setState({devices: data.resp, deviceName: data.deviceName})
console.log(data)
}
render() {
...
}
componentDidUpdate(prevProps) {
}
...
I expect to set the state from callbacks inside the event handler
Error screenshot
That is because you have not bound the function callback1 to this. So in your constructor you should bind it the same way you bind your other functions.
An alternative way is to make callback1 an arrow function instead so that it does not have to be bound. That would look like this:
callback1 = () => {
this.setState({devices: data.resp, deviceName: data.deviceName})
console.log(data)
}

Fetching methods depends on each other

I have been trying to fetch data from two sources in componentDidMount and second component's url relies on the data fetched from the first component, but it looks that state is not "updated" inside ComponenDidMount. I have tried to resolve it by using fetchDuel() in the constructor with no luck. Any suggestions? Thanks in advance!
class DuelDetail extends React.Component {
state = {
duel: [],
dataset: null
};
fetchDuel = () => {
const duelID = this.props.match.params.duelID;
axios.get(`http://127.0.0.1:8000/api/duel/${duelID}`,
{'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
.then(res => {
this.setState({
duel: res.data
});
});
};
fetchDataset = () => {
axios.get(`http://127.0.0.1:8000/api/dataset/${this.state.duel.dataset}`,
{'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
.then(res => {
this.setState({
dataset: res.data
});
});
};
componentDidMount() {
this.fetchDuel()
this.fetchDataset()
}
Just call the second function in the then() block of the first and pass the data as a param. setState is asynchronous so you can't rely on the data to be set immediately.
fetchDuel = () => {
const duelID = this.props.match.params.duelID;
axios.get(`http://127.0.0.1:8000/api/duel/${duelID}`,
{'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
.then(res => {
this.setState({
duel: res.data
});
this.fetchDataset(res.data);
});
};
As the 2 actions are async you need to handle it accordingly.
Axios get returns a promise .So you can call the second action in the then block of the first action.
Also, setState is an aync action.(It gets queued up and doesn't get triggered instantly).
Use the data received from the first action, in its then block, pass it to the second action
Just call the second function in the .then() of the first function using data from the response. Example:
class DuelDetail extends React.Component {
state = {
duel: [],
dataset: null
};
fetchDuel = () => {
const duelID = this.props.match.params.duelID;
axios.get(`http://127.0.0.1:8000/api/duel/${duelID}`,
{'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
.then(res => {
this.setState({
duel: res.data
});
this.fetchDataset(res.data.dataset)
// pass whatever property you get from the response here.
});
};
fetchDataset = (datasetId) => {
axios.get(`http://127.0.0.1:8000/api/dataset/${datasetId}`,
{'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
.then(res => {
this.setState({
dataset: res.data
});
});
};
componentDidMount() {
this.fetchDuel()
}

Resources