Skip to content

Instantly share code, notes, and snippets.

@colorfield
Last active January 16, 2018 21:44
Show Gist options
  • Save colorfield/bba9123cfa21060b379a5348c2f119a1 to your computer and use it in GitHub Desktop.
Save colorfield/bba9123cfa21060b379a5348c2f119a1 to your computer and use it in GitHub Desktop.
React fetch on the component
import React from 'react';
import Layout from '../../components/Layout';
import ItineraryListPage from './ItineraryListPage';
const title = 'Audioguide';
async function action({ locale }) {
const languageId = locale.substring(0, 2);
return {
chunks: ['itineraries'],
title,
component: (
<Layout>
<ItineraryListPage title={title} languageId={languageId} />
</Layout>
),
};
}
export default action;
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './ItineraryListPage.css';
import ItineraryTeaser from '../../components/ItineraryTeaser';
import ItineraryListHeader from '../../components/ItineraryListHeader';
import { JSON_API_URL } from '../../constants/env';
class ItineraryListPage extends React.Component {
static propTypes = {
languageId: PropTypes.string.isRequired,
};
/**
* Returns the JSON API endpoint.
*
* @returns {string}
*/
static getItinerariesEndpoint(languageId) {
return `${JSON_API_URL}/${languageId}/jsonapi/taxonomy_term/audio_itinerary?filter[field_is_parent][value]=1&filter[langcode][value]=${languageId}&sort=weight&include=field_image`;
}
constructor(props) {
super(props);
this.state = {
itineraries: [],
itinerariesWithIncluded: [],
hasError: false,
isLoading: true,
};
}
componentDidMount() {
const endpoint = ItineraryListPage.getItinerariesEndpoint(
this.props.languageId,
);
this.fetchItineraries(endpoint);
}
componentWillReceiveProps(nextProps) {
if(nextPropos.languageId !== this.props.languageId) {
const endpoint = ItineraryListPage.getItinerariesEndpoint(
nextProps.languageId,
);
this.fetchItineraries(endpoint);
}
}
/**
* Helper that gets the first image from an included field.
*
* @param imageId
* @returns {*}
*/
getImageFromIncluded(imageId) {
let result = null;
const image = this.state.itineraries.included.filter(
obj => obj.id === imageId,
);
if (image[0]) {
result = `${JSON_API_URL}/${image[0].attributes.url}`;
}
return result;
}
/**
* Attaches the includes Url to the itineraries data.
*/
setItinerariesWithIncludedUrl() {
const itinerariesWithIncluded = [];
this.state.itineraries.data.forEach(itinerary => {
const tmpItinerary = itinerary;
if (itinerary.relationships.field_image.data !== null) {
const iconImageId = itinerary.relationships.field_image.data.id;
tmpItinerary.iconImageUrl = this.getImageFromIncluded(iconImageId);
}
itinerariesWithIncluded.push(tmpItinerary);
});
this.setState({ itinerariesWithIncluded });
}
/**
* Fetches itineraries data.
*
* @param endpoint
*/
fetchItineraries(endpoint) {
this.setState({ isLoading: true });
fetch(endpoint)
.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
this.setState({ isLoading: false });
return response;
})
.then(response => response.json())
// ES6 property value shorthand for { itineraries: itineraries }
// and use the second parameter as a callback
.then(itineraries =>
this.setState({ itineraries }, this.setItinerariesWithIncludedUrl),
)
.catch(() => this.setState({ hasError: true }));
}
render() {
if (this.state.hasError) {
return <p>Error while loading itineraries.</p>;
}
if (this.state.isLoading) {
return <p>Loading...</p>;
}
return (
<div>
<div className={s.container}>
<ItineraryListHeader />
<ul className={s.gridPage}>
{this.state.itinerariesWithIncluded.map(itinerary => (
<li key={`${itinerary.id}-${this.props.languageId}`}>
<ItineraryTeaser
destination={`/itinerary/${itinerary.id}`}
itinerary={itinerary}
/>
</li>
))}
</ul>
</div>
</div>
);
}
}
export default withStyles(s)(ItineraryListPage);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment