Skip to content Accessibility

Redux Standard Props

Organize Redux specific props in components under a dedicated namespace.

Published

Categories

Components connected to Redux have three types of props:

  1. values that derive from reducers
  2. functions that dispatch actions
  3. values/functions that make up a components public API

The props passed to the Films component below best illustrates this:

Programming language (abbreviated): jsx

const Films = ({
genre,
films,
hasRecommendToFriend,
onWatchLater,
onPlay
}
) => {
const [film, setFilm] = useState("");
const handleFilm = ({ target: { value } }) => setFilm(value);

const handleSubmit = event => {
event.preventDefault();

onWatchLater(film);
};

return (
<form onSubmit={handleSubmit}/>
<h3/>{genre}</h3/>

<select value={film} onChange={handleFilm}/>
{films.map(({ id, title }) => (
<option key={id} value={id}/>
{title}
</option/>
))}
</select/>

{hasRecommendToFriend && film && <RecommendToFriend film={film} />}

<button type="button" onClick={onPlay}/>
Play
</button/>
<button/>Watch Later</button/>
</form/>
);
};

const mapStateToProps = ({ genre, films }) => ({
genre,
films
});

const mapDispatchToProps = dispatch => ({
onWatchLater: film => dispatch(watchLater(film))
});

One thing the different types of props lack is an identity.

It is difficult to understand where each prop comes from without digging into the code. Is genre passed from a parent component or does it derive from a reducer? Is onWatchLater a prop callback or an action?

A quick scan of mapStateToProps and mapDispatchToProps reveals prop types 1 and 2, which subsequently surfaces prop type 3 (by process of elimination) however there's a fair amount of flip-flopping involved.

This can be remedied by grouping Redux specific props under a dedicated namespace:

Programming language (abbreviated): js

store: {
// holds values derived from reducers
},
actions: {
// holds functions that dispatch actions
}

Below is a revised version of the Films component using this approach:

Programming language (abbreviated): jsx

const Films = ({
store,
actions,
hasRecommendToFriend,
onPlay
}
) => {
const [film, setFilm] = useState("");
const handleFilm = ({ target: { value } }) => setFilm(value);

const handleSubmit = event => {
event.preventDefault();

actions.onWatchLater(film);
};

return (
<form onSubmit={handleSubmit}/>
<h3/>{store.genre}</h3/>

<select value={film} onChange={handleFilm}/>
{store.films.map(({ id, title }) => (
<option key={id} value={id}/>
{title}
</option/>
))}
</select/>

{hasRecommendToFriend && film && <RecommendToFriend film={film} />}

<button type="button" onClick={onPlay}/>
Play
</button/>
<button/>Watch Later</button/>
</form/>
);
};

const mapStateToProps = ({ genre, films }) => ({
store: {
genre,
films
}
});

const mapDispatchToProps = dispatch => ({
actions: {
onWatchLater: film => dispatch(watchLater(film))
}
});

Now it is explicitly clear that store.films comes from Redux state and actions.onWatchLater dispatches an action. All other props (those not within the store and actions namespace) make up the components public API, which are usually the props consumers care most about.

About the author

I'm Callum, a Front-end Engineer at Nutmeg. Previously I wrote code for KAYAK, American Express, and Dell. Out of hours I publish blog posts (like this one) and tweet cherry-picks.

Feel free to follow or message me at @_callumhart on Twitter.