Skip to content

Instantly share code, notes, and snippets.

@sfrdmn
sfrdmn / mcr_post_13.jsx
Created December 1, 2017 16:02
mcr_post_13
const { createSelector, createStructuredSelector } = require('reselect')
const identity = x => x
const createAsyncSelector = (
asyncSelectors = {},
syncSelectors = {},
compute = identity
) => {
// Let’s do a little argument dance to optionally support the uniform
// handling of synchronous selectors (selectors on data not conforming
@sfrdmn
sfrdmn / mcr_post_12.jsx
Created December 1, 2017 16:02
mcr_post_12
const FoodList = ({ loaded, data }) => {
if (!loaded) {
return <Spinner />
}
const { foodItemsWithFacts } = data;
return (
<ul className="food-list">
{
@sfrdmn
sfrdmn / mcr_post_11.jsx
Created December 1, 2017 16:01
mcr_post_11
const getAsyncFoodItemsWithFacts = createAsyncSelector(
{
foodItems: getAsyncFoodItems,
funFactsById: getFunFactsById
},
({ foodItems, funFactsById }) => (
mergeFunFactsIntoFoodItems(foodItems, funFactsById)
))
)
@sfrdmn
sfrdmn / mcr_post_10.jsx
Created December 1, 2017 16:00
mcr_post_10
const getFoodItemListViewState = createAsyncSelector({
foodItems: getAsyncFoodItems,
funFactsById: getAsyncFunFactsById
})
@sfrdmn
sfrdmn / mcr_post_09.jsx
Created December 1, 2017 16:00
mcr_post_09
const getAsyncFoodItems = state => state.foodItems
const getAsyncCookware = state => state.cookware
// Let’s introduce a new async resource containing fun facts about food
const getAsyncFunFactsById = state => state.funFactsById
@sfrdmn
sfrdmn / mcr_post_08.jsx
Created December 1, 2017 15:59
mcr_post_08
const { combineReducers } = require('redux')
const foodItemsLoadState = loadStateReducer({
FOOD_ITEMS_FETCH_PENDING: 'pending',
FOOD_ITEMS_FETCH_ERROR: 'error',
FOOD_ITEMS_FETCH_COMPLETE: 'complete'
})
const foodItemAddState = loadStateReducer({
FOOD_ITEMS_ADD_PENDING: 'pending',
@sfrdmn
sfrdmn / mcr_post_07.jsx
Created December 1, 2017 15:59
mcr_post_07
// Similar to the higher-order action creator, we accept a mapping of async
// states and action types, except this time, for convenience, in reverse.
// We then yield a reducer
const loadStateReducer = (asyncStates) => {
return (state = { loading: false, loaded: false, data: null }, action) {
const asyncState = asyncStates[action.type]
switch (asyncState) {
case 'pending':
return {
@sfrdmn
sfrdmn / mcr_post_06.jsx
Created December 1, 2017 15:58
mcr_post_06
const fetchFoodItems = createActionCreator(
{
pending: FOOD_ITEMS_FETCH_PENDING,
complete: FOOD_ITEMS_FETCH_COMPLETE,
error: FOOD_ITEMS_FETCH_ERROR,
},
() => () => foodService.fetchFoodItems()
)
const addFoodItem = createActionCreator(
@sfrdmn
sfrdmn / mcr_post_05.jsx
Created December 1, 2017 15:57
mcr_post_05
// Here we have a function which accepts a map of async states to action types
// as well as a thunk creator. It will yield a new thunk creator which wraps
// the provided one with our async state logic
const asyncActionCreator = (asyncTypes, createThunk) => (...args) => {
const thunk = createThunk(...args);
return (dispatch) => {
dispatch({ type: asyncTypes.pending })
// We assume here that the wrapped thunk produces a Promise
@sfrdmn
sfrdmn / mcr_post_04.jsx
Created December 1, 2017 15:57
mcr_post_04
const FOOD_ITEMS_FETCH_PENDING = 'FOOD_ITEMS_FETCH_PENDING'
const FOOD_ITEMS_FETCH_COMPLETE = 'FOOD_ITEMS_FETCH_COMPLETE'
const FOOD_ITEMS_FETCH_ERROR = 'FOOD_ITEMS_FETCH_ERROR'
const FOOD_ITEMS_ADD_PENDING = 'FOOD_ITEMS_ADD_PENDING'
const FOOD_ITEMS_ADD_COMPLETE = 'FOOD_ITEMS_ADD_COMPLETE'
const FOOD_ITEMS_ADD_ERROR = 'FOOD_ITEMS_ADD_ERROR'
// …
const addFoodItem = item => (dispatch) => {