I'm learning redux (in Flutter using Firestore, but I don't think that matters), trying to get beyond the basics, and I'm confused about where 'computed state' (not even sure what to call it) should go.
Say I have app state like this:
I'm able to set user (login success action) and request user's movies (login success middleware). When the movies query completes, I'm confused about where to initialize recentFavoriteMovie
. There seems to be many choices....
Are all or any of these valid choices? I hope this makes sense as a question. I might even be too behind the curve to ask this properly.
You almost ther with computed state. From documentation
Reselect provides a function
createSelector
for creating memoized selectors.createSelector
takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is changed in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.
That is essentially what yu want with lazy selection of movies.
In state you store user and movies. Some movies marked as favorites for specific user (so when user marks movie as favorite you only modify movies and not re-run selector).
When some component needs list of favorite movies, it calls selector which computes derived state (list of favorite movies) and returns it. Also selector will memorize results and recompute them only when store changes but not on each render.
This approach can be considered best practice as you may later implement some filters for movies list and selectors will help to extract filtered list of movies.
When using selector you don't required to store selected data (list of favorite movies) in you store.
Computed state is used in mapStateToPros
for each component that require computed state like so
const makeMapStateToProps = () => {
const getFavoriteMovies = makeGetFavoriteMovies();
const mapStateToProps = (state) => (
{
favoriteMovies: getFavoriteMovies(state.user, state.movies),
movies: state.movies,
user: state.user
});
return mapStateToProps;
}
And makeGetFavoriteMovies
may look like
const getFavoriteMovies = (state) => state.movies;
const getUser = (state) => state.user;
export function makeGetFavoriteMovies () {
return createSelector(
[getFavoriteMovies, getUser],
(favoriteMovies, user) => {
// Here can be complicated logic to select only favorite movies
return movies.filter (movie => movie.isFavorite);
}
);
)
Reducer and/or middleware can compute favorite movies list. But this is not their responsibility. So to better separate concerns its better to use selectors for this task.
Also there is not reason for specific middleware (ogin success middleware). You may implement logic in actions and reducer.