📌 Learning objectives:
- learn how to talk to an API
- get familiar with more libraries
- learn the basics of client-side routing
The Fetch API provides an interface for fetching resources (including across the
network). R.I.P. XMLHttpRequest
!
Documentation: MDN Fetch API
fetch('https://example.org/api/endpoint')
.then((response) => {
if (response.status >= 200 && response.status < 300) {
return response.json();
}
throw new Error(response.statusText);
})
.then((json) => {
// do something with the `json` data
});
We have to rely on a polyfill to use the fetch
API:
$ yarn add isomorphic-fetch
The best feature of middleware is that it is composable in a chain. Redux middleware provides (third-party) extension points between dispatching actions and the moment reducers are reached.
Documentation: Redux Middleware
Redux Thunk middleware allows you to write action creators that return a function instead of an action. It is useful to create asynchronous actions (API calls).
$ yarn add redux-thunk
export const callAPI = id => {
return dispatch => {
dispatch({ type: CALL_API_STARTED });
return fetch(`https://example.org/api/endpoint/${id}`)
.then((response) => {
// TODO: throw Error when response is not successful
return response.json();
})
// only executed when request is OK
.then(json => dispatch(loadResults(json)))
// request has failed
.catch(error => dispatch(displayError(error)))
// always executed
.then(() => dispatch({ type: CALL_API_FINISHED }))
;
};
};
Redux Persist allows to automatically
persist and rehydrate a Redux store (in localStorage
for example).
$ yarn add redux-persist@4
const isNotProduction = process.env.NODE_ENV !== 'production';
// The code below is new.
const enableDevTools =
isNotProduction &&
'undefined' !== typeof window &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
if (isNotProduction) {
// ...
}
// The code below is new.
const composeEnhancers = enableDevTools
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: compose; // import `compose` from `redux`
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(
rootReducer,
initialState,
composeEnhancers(autoRehydrate())
);
persistStore(store);
return store;
}
Redux Persist is not a middleware per se but an enhancer. It adds extra
functionality to the store when you call createStore()
.
Middleware enhances the store at the dispatch()
level.
Ensembl is a project to automate the annotation of the human genome. They expose a REST(-ish) API. Given a "Ensembl stable ID", it is possible to retrieve a sequence.
You can find Ensembl identifiers on this
page
(ENSG...
).
$ http --json http://rest.ensembl.org/sequence/id/ENSG00000274347
(Install HTTPie if you do not use it yet)
- Install
redux-thunk
andisomorphic-fetch
- Create a
EnsemblSearch
component that renders aform
with a search bar (input
) and abutton
to trigger the search - Create a
ensembl
reducer that fetches a sequence from the Ensembl API given an identifier. Error handling is at the very least aalert()
call - The
button
should be disabled when input is empty and should be replaced by a loading message when API is called
- Add
redux-persist
to your project
On the server, routing refers to determining how an application responds to a particular client request.
On the client, it is similar: deciding which "view" to display according to the URL browsed by the user.
React Router is a third-party library allowing to deal with different "pages" in your application, in a very React way.
yarn add react-router-dom
Documentation: React Router (web)
ReactDOM.render(
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
{/* ... */}
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
</Router>
);
A <Switch>
component renders the first child <Route>
that matches. A
<Route>
with no path always matches.
ReactDOM.render(
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route component={NotFound} />
</Switch>
</Router>
);
- Create a new
About
component with some content - Add
react-router-dom
and configure the routing into your application (you will have to update theHeader
component too) - Add a
NotFound
component to catch404
errors
- Rename the
App
component toHome
- Move your routing code (inside
Router
) into asrc/Seqbook.js
file