Reputation: 1603
I was tasked to create a front-end for a poc. I am not a front end developer but I chose to use React JS. There is only one page fetching data from multiple API endpoints. API endpoints return a simple json object. I managed to get that to work however my code is ugly af and I want to create a function to handle all of that but I can't seem to get it right. Here's my code
export default class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
group1: [],
group2: [],
group3: [],
isLoaded: false,
}
}
componentDidMount() {
const group1_url = "http://localhost/api/1"
const group2_url = "http://localhost/api/2"
const group3_url = "http://localhost/api/3"
fetch(group1_url)
.then(res => res.json())
.then(json => {
this.setState({
group1: json,
})
});
fetch(group2_url)
.then(res => res.json())
.then(json => {
this.setState({
group2: json,
})
});
fetch(group3_url)
.then(res => res.json())
.then(json => {
this.setState({
group3: json,
})
});
}
I am trying to create a function like this:
function fetch_data(url, state) {
fetch(url)
.then(res => res.json())
.then(json => {
this.setState({
state: json,
})
});
}
var group1 = fetch_data(group1_url, group1);
So far no joy. How can I create a function to fetch data and set a state in js? Alternatively how can I make my code look better? Or is there something else I should use/look into?
Upvotes: 1
Views: 1814
Reputation: 4998
You could try Promise.all
Promise.all takes an array of promises (it technically can be any iterable, but is usually an array) and returns a new promise.
const points = [
"http://localhost/api/1",
"http://localhost/api/2",
"http://localhost/api/3",
];
const responses = await Promise.all(points.map((point) => fetch(point)));
const data = await Promise.all(responses.map((response) => response.json()));
const [group1, group2, group3] = data;
this.setState({
group1,
group2,
group3,
});
Just remember to wrap this logic in an async function
Upvotes: 2
Reputation: 370729
Pass a string as the second parameter, and use a computed property:
function fetch_data(url, state) {
fetch(url)
.then(res => res.json())
.then(json => {
this.setState({
[state]: json,
})
});
}
fetch_data(group1_url, 'group1');
I'd also highly recommend catching errors - possible unhandled rejections should be avoided whenever possible.
You might want to use Promise.all
to wait for all groups to load:
const dataSources = {
group1: 'http://localhost/api/1',
group2: 'http://localhost/api/2',
group3: 'http://localhost/api/3',
};
Promise.all(
Object.entries(dataSources).map(([propertyName, url]) => (
fetch(url)
.then(res => res.json())
.then((result) => {
this.setState({
[propertyName]: result
})
})
))
)
.then(() => {
this.setState({ isLoaded: true })
})
.catch((error) => {
// handle errors
})
(also note that your json
argument is not a JSON - JSON is only a format that exists with strings. Something that has been deserialized is just a plain object or array. Better to call it something less misleading, like result
as I did)
Upvotes: 2
Reputation: 1883
You can do something like this.
function fetch_data(url, state) {
fetch(url)
.then(res => res.json())
.then(json => {
this.setState({
[state]: json,
})
});
}
var group1 = fetch_data(group1_url, 'group1');
Upvotes: 1