Last active
January 16, 2018 21:44
-
-
Save colorfield/bba9123cfa21060b379a5348c2f119a1 to your computer and use it in GitHub Desktop.
React fetch on the component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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