Fetching Memories

You're ready to pitch those placeholder memories and get the real ones from the web service. As soon as the app loads, you'll dispatch a thunk that fetches the day's memories and adds them to the store.

A good first step is to add the thunk middleware to the store:

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';

// ...

export const store = createStore(reducer, initialState, applyMiddleware(thunk));

You need a thunk creator that calls fetch. The endpoint of the web service expects the month and day as URL components, so you make your thunk creator take these as parameters. The file src/actions.js is a reasonable place to put this thunk creator since thunks are dispatched like actions and they themselves dispatch actions. You drop this code in that file:

function assertResponse(response) {
if (response.status >= 200 || response.status < 300) {
return response;
} else {
throw new Error(`${response.status}: ${response.statusText}`);
}
}

export function fetchDay(month, day) {
return dispatch => {
fetch(`https://example.com:8443/memories/${month}/${day}`)
.then(assertResponse)
.then(response => response.json())
.then(data => {
if (data.ok) {
dispatch(showMemories(data.results));
} else {
console.error(data);
}
});
};
}

You replace example.com with your actual domain.

Once the memories are unpacked, you dispatch an action that replaces the current memories in the store with the ones that have just been fetched. You create an action enum and an action creator:

export const Action = Object.freeze({
ShowMemories: 'ShowMemories',
});

export function showMemories(memories) {
return {type: Action.ShowMemories, payload: memories};
}

When the reducer sees a ShowMemories action, it makes a new state object that includes the fetched memories from the action's payload:

// ...
import {Action} from './actions';

function reducer(state, action) {
switch (action.type) {
case Action.ShowMemories:
return {
...state,
memories: action.payload,
};
default:
return state;
}
}

// ...

The App component will re-render since the state it depends on has changed. It will select out the new memories and turn them into Memory components.

All that remains is to dispatch the fetch thunk. React's useEffect function is your vehicle for scheduling one-time initialization routines. You register an effect function that loads in the memories for the current day:

import {fetchDay} from './actions';

function App() {
const memories = useSelector(state => state.memories);
const dispatch = useDispatch();

useEffect(() => {
const today = new Date();
dispatch(fetchDay(today.getMonth() + 1, today.getDate()));
}, [dispatch]);

// ...
}

After you make these changes, you probably see a blank viewport because you don't have any memories in the database yet. Try adding some memories for the current day but in different years using curl or your SQL interpreter. Do you see them appear when you reload your client app?

Currently you can only see the current date and you can't add any memories. To fix both of these problems, you decide to add a toolbar.