We finally come to the last part of this small introduction to React. Logically I have left many things in the pipeline, so I do not rule out writing more posts in the future where we’ll be focusing on different aspects of the JS development stack, but I think that with this last post you will already have the basic notions necessary to grow and get better on your own.
Last week we ended up things at a very interesting point. Our goal was to create a small application with multiple counters, which you could add or remove at will:

By the time we ended last post we had an amazing store to keep track of our application’s state. This means we already have all the basics we need to finally build the UI.
Today we will see how to connect React components with our Redux-based WordPress store so that the interface shows the state we have in the store and so that user interactions update said state.
Solution to Last Week’s Homework
But before we do so, let’s quickly review the homework I left you with last week. Essentially, I asked you to re-implement the store so that it no longer uses a dictionary, but an array of objects:
const originalStore = {
x: 1,
y: 2,
};
const newStore = [
{ id: 'x', value: 1 },
{ id: 'y', value: 2 },
];
What changes did you do to apply this update to your store? Well, let’s review them all quickly!
Actions
Store actions are exactly the same as those we already had, so I hope you didn’t change anything here, as it wasn’t needed. As you saw last week, actions don’t update (nor access) the store directly, and therefore any changes on the underlying structure of our store won’t have any effect here.
Action are simple functions that generate an object that signals an “update request,” and that’s precisely what we still have in our actions.js
file:
export function addCounter( counterId ) {
return {
type: 'ADD_COUNTER',
counterId,
};
}
export function removeCounter( counterId ) {
return {
type: 'REMOVE_COUNTER',
counterId,
};
}
export function setCounterValue( counterId, value ) {
return {
type: 'SET_COUNTER_VALUE',
counterId,
value,
};
}
Reducer
The reducer is the function responsible for updating the state based on the previous state and a dispatched action. In this case, since we want to change the data structure that stores the state of our application, we do need to re-implement the reducer:
import { map, find, without } from 'lodash';
export default function reducer( state = [], action ) {
switch ( action.type ) {
case 'ADD_COUNTER':
return [
...state,
{ id: action.counterId, value: 0 },
];
case 'REMOVE_COUNTER':
return without(
state,
find( state, { id: action.counterId } )
);
case 'SET_COUNTER_VALUE':
return map(
state,
( counter ) =>
action.id === action.counterId
? { ...counter, value: action.value }
: counter
);
}
return state;
}
As you can imagine, all we had to do here was to change the default value of the state from the empty object {}
to an empty array []
. Then, we simply need to set each case
in our switch
block so that actions update the new store correctly. Essentially, this is adding, removing, or updating objects in the array.

Nelio Forms
A fantastic contact plugin using the block editor. In its simplicity lies the true power of this plugin. I love it, very versatile and it worked perfectly for me.

Wajari Velasquez
Selectors
Finally, we have our selectors.js
file. As we saw last week, a selector receives the current state of our application and any other parameters we might need, and retrieves the requested value from this state. Since we changed how the state is stored, we also need to change the body of our selectors:
import { map, find } from 'lodash';
export function getCounterIds( state ) {
return map( state, 'id' );
}
export function getCounterValue( state, counterId ) {
const counter = find( state, { id: counterId } ) || {};
return counter.value;
}
Again, it’s no big deal… but I hope you got this one right 🙂
In our example we only had two selectors, so we only have to reimplement two functions. The first is responsible for returning the identifiers of all our counters, which we can very easily achieve with map
. The second returns the value of the specified counter (or undefined
if the given counterId
can’t be found in our store), so all you have to do is search for the counter whose id
is counterId
using Lodash’s helper function find
and return the value
attribute of the related counter (if any).
One Last Note
The reason I asked you to tweak your store was so that you could learn the following lesson: the main advantage of using stores like this one is that they behave like black boxes—you can completely change how it’s internally organized and everything will work as expected, as long as its interface (i.e. actions and selectors) don’t change.
Re-Writing the Components of Our UI
We want our users to be able to add and remove counters at their will:

and manage each counter independently from each other. What changes do we need to apply to what we had in the UI we implemented in part 2? Well, we obviously need to (1) modify each counter to include a Delete button and (2) tweak the app so that there’s a new button to add new counters. So let’s do this!
First, open the file src/components/counter.js
and add the new Delete button and a new prop
onDelete
so that, when the user clicks on the button, the counter is deleted:
const Counter = ( { value, onIncrease, onDecrease, onDelete } ) => (
<div>
<div>Counter: <strong>{ value }</strong></div>
<button onClick={ onIncrease }>+</button>
<button onClick={ onDecrease }>-</button>
<button onClick={ onDelete }>Delete</button>
</div>
);
export default Counter;
Next, create a new component that will be responsible for rendering (a) all the counters the user added and (b) the button for adding new ones. I recommend creating a src/components/counter-list.js
file as follows:
import Counter from './counter';
const CounterList = ( { addCounter, counterIds } ) => (
<div>
{ counterIds.map( ( id ) => (
<Counter key={ id } counterId={ id } />
) ) }
<button onClick={ addCounter }>Add Counter</button>
</div>
);
export default CounterList;
This new component has a few interesting things worth mentioning:
- It’s a component (
CounterList
) that uses another component (Counter
). We didn’t see any examples of this in our tutorial yet so… now you have one! The only thing you need to remember is that you’ll have toimport
all the components you want to use. - Our
import
statement doesn’t have curly braces (import Counter vs import {Counter}), even though all the imports we used so far did. That’s because Counter is a default export now, and default exports aren’t imported with curly braces. - The CounterList component receives two properties: addCounter is the action that allows us to add new counters and counterIds is an array with the identifiers of all the counters our app has.
- To render each counter, we map the array of IDs to Counter instances.
- In this map, the Counter component has two new properties: key and counterId. key is a prop required by React to optimize its rendering engine. counterId is something that will discuss later on.
- The
Counter
component doesn’t include any of the props it expects. That’s because we’ll populate them using the store (and the new propcounterId
will help us with that). - Like
Counter
,CounterList
is an export default.
Main File
Since our app does no longer show a single counter, but a list of counters, we need to tweak index.js
so that it renders the new component we just created: CounterList
. Moreover, we can also get rid of all the code we wrote in part 2 to manage the state of our single counter, because we now have a proper WordPress store.
Taking all this into account, this is how index.js
should look like:
// Import dependencies
import { render } from '@wordpress/element';
import './store';
import CounterList from './components/counter-list';
// Render component in DOM
const wrapper = document.getElementById( 'react-example-wrapper' );
render( <CounterList />, wrapper );
As you can see, we simply import our store and the CounterList
component and we render the latter (using the render
function of the @wordpress/element
package) in a DOM node.
Unfortunately, nothing works as expected (yet), but that’s because we haven’t connected any of our components to the store.
How to Connect React Components to a Redux Store
Cool! Everything we need is ready and we’re just one step away from our goal. On the one hand, we have a store with selectors to query the state of our application and actions to update it. On the other hand, we have the necessary components to visualize this state in the UI. The only thing that’s missing is glueing the two pieces together…
Connecting CounterList
to the Store
CounterList
is a simple component that requires two properties. On the one hand, it expects a list with the identifiers of all the components that we have active in our application: counterIds
. On the other hand, it also expects a callback with which to add new counters: addCounter
.
If you take a look at the selectors and the actions we defined in our store in part 3 of the tutorial, you will see we do have such a selector and action. The store does indeed have the getCounterIds
selector, which returns “a list with the identifiers of all the components we have.” It also has the addCounter
action, which adds a new counter in our app (provided you give it a unique identifier). So let’s see how we can use those in our component.
The @wordpress/data
package, which we already use to register the store, offers a couple of high-order components to extend an existing component with properties derived from a store: withSelect
and withDispatch
. This means that, by applying withSelect
and/or withDispatch
on a component, we can augment said component with the props
we want using values defined in a store.
Let’s see this with an example:
import { withSelect, withDispatch } from '@wordpress/data';
import { v4 as uuid } from 'uuid';
import Counter from './counter';
const CounterList = ( { addCounter, counterIds } ) => (
<div>
{ counterIds.map( ( id ) => (
<Counter key={ id } counterId={ id } />
) ) }
<button onClick={ addCounter }>Add Counter</button>
</div>
);
const withCounterIds = withSelect( ( select ) => {
const { getCounterIds } = select( 'react-example/counters' );
return {
counterIds: getCounterIds(),
};
} );
const withCounterAdder = withDispatch( ( dispatch ) => {
const { addCounter } = dispatch( 'react-example/counters' );
return {
addCounter: () => addCounter( uuid() ),
};
} );
export default withCounterAdder( withCounterIds( CounterList ) );
I know there’s a lot of things going on here, so let’s take it one step at a time:
- The first thing we do in the extended version of
CounterList
isimport
the new dependencies we need. Specifically, we importwithSelect
andwithDispatch
. Then, we have a weird import:uuid
. This is a package that generates unique random identifiers, and you’ll see why we need it in a bit. - The component itself (
CounterList
) didn’t change. It still assumes it’ll get the two props it needs to render the UI: a list of counter IDs and an action to add new counters. - Next, we use
withSelect
.withSelect
is a higher-order component, but you can think of it as “a function that returns another function.” The resulting function is something that will augment the capabilities of an existing component (keep reading and it’ll all make sense soon).- In order to use
withSelect
, you must first call it with a function as a parameter. In our case, we have created an anonymous function. - The anonymous function has an argument,
select
, that lets you access all the selectors registered in your stores. - The first thing we do in this anonymous function is retrieve the
getCounterIds
selector from ourreact-example/counters
store. - The result of this anonymous function are the props we want to add to our
CounterList
component. In this case, it’s simply the list of identifierscounterIds
, whose values were retrieved bygetCounterIds
. - We save the result of
withSelect
(remember, this result is a higher-order component, or a new function if you will) in a variable calledwithCounterIds
. We can now apply this higher-order component/function to any component we like as follows:withCounterIds(MyComponent)
. The result of doing so is thatMyComponent
will now have the propertycounterIds
properly set with a value retrieved from thereact-example/counters
store.
- In order to use
- Then we use the
withDispatch
higher-order component/function. Its operation is exactly the same aswithSelect
, but instead of giving us access to store selectors, it gives us access to its actions.withDispatch
, likewithSelect
, expects a function as a parameter.- Its first parameter is now called
dispatch
. We use it to access store actions. - Using
dispatch
, we get theaddCounter
action from ourreact-example/counters
store. - The
addCounter
function our component expects is a function with no arguments. TheaddCounter
action from our store, however, does need an argument: the unique identifier the new counter should have. To solve this mismatch, all we need to do is return an anonymous function that matches the prop ourCounterList
components expect (i.e. a function with no arguments) whose execution will call the actual action in the store. Since the action in the store needs a unique identifier, we use the packageuuid
to generate a unique ID every time we call the propaddCounter
. withCounterAdder
is the result of thiswithDispatch
, and is analogous towithCounterIds
. Applying this higher-order component to an existing component will provide the existing component with anaddCounter
prop, which is exactly what we wanted.
- Finally, we extend our
CounterList
component by first applying thewithCounterIds
higher-order component (so thatCounterList
receives a list ofcounterIds
) and then we applywithCounterAdder
(so that it receives theaddCounter
prop).
And that’s it! You’ve now successfully connected your first component with a store, which means you should now be able to add counters (and see them) in your UI.
Connecting each Counter
to the Store
Now let’s tweak our Counter
component so that it gets the props it needs from the store. As you can imagine, all we need to do is repeat the process we just did: use a few selectors and actions from react-example/counters
via withSelect
and withDispatch
and apply the resulting higher-order components to Counter
.
Let’s start by looking at the final source code:
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
const Counter = ( { value, onDelete, onIncrease, onDecrease } ) => (
<div>
<div>Counter: <strong>{ value }</strong></div>
<button onClick={ onIncrease }>+</button>
<button onClick={ onDecrease }>-</button>
<button onClick={ onDelete }>Delete</button>
</div>
);
const withValue = withSelect( ( select, { counterId } ) => {
const { getCounterValue } = select( 'react-example/counters' );
return {
value: getCounterValue( counterId ),
};
} );
const withActions = withDispatch( ( dispatch, { counterId, value } ) => {
const {
setCounterValue,
removeCounter,
} = dispatch( 'react-example/counters' );
return {
onIncrease: () => setCounterValue( counterId, value + 1 ),
onDecrease: () => setCounterValue( counterId, value - 1 ),
onDelete: () => removeCounter( counterId ),
};
} );
export default compose( withValue, withActions )( Counter );
- First of all, we
import
the dependencies we’ll need. - The component itself,
Counter
, doesn’t change either. It still expects four props:value
,onDelete
,onIncrease
, andonDecrease
, which we now know will get from the store. - First, use
withSelect
to retrieve thevalue
of the counter from our store.- The store maintains the values of many counters, so we have to tell it exactly which counter we want. Luckily, when
CounterList
mapped each counter ID to a component, we rendered eachCounter
with acounterId
prop, remember? Well, that’s how we can tell our store the exact value we’re interested in… - The body of this anonymous function is very similar to the example we have seen with
CounterList
. We simply get thegetCounterValue
selector from our store and return the correctvalue
using thecounterId
prop. Notice that the anonymous function has now a second argument: the list ofprops
of the component.
- The store maintains the values of many counters, so we have to tell it exactly which counter we want. Luckily, when
- Next, we use
withDispatch
to populate the actions ourCounter
needs.- In our store, we know that we have the
setCounterValue
andremoveCounter
actions. - Both actions need the identifier of the counter to update or delete, which, as we have just seen, is available in the second argument of the anonymous function we defined in
withDispatch
. setCounterValue
also needs to know the new value we want to set. Since ourCounter
component needs to functions (one to increase and another one to decrease its current value), we also need to know what the current value is so that we can add (or substract) one. Luckily, we just retrieved the current value of the counter usingwithSelect
, which means there’s a prop namedvalue
.- The result of applying
withDispatch
is a higher-order component that will have the three functions our component expects:onIncrease
is an anonymous function that adds1
to the current value ofcounterId
;onDecrease
is another anonymous function that does the same thing, but subtracting1
; andonDelete
is a function that uses theremoveCounter
action from the store.
- In our store, we know that we have the
- Finally, we apply the higher-order components we’ve just created (
withValue
andwithActions
) to ourCounter
component. This time I’ve used thecompose
helper function provided by@wordpress/compose
, but please notice it’s exactly the same thing we did before withCounterList
.
And that’s it! You now have a working example with several components that react to and modify a store!
In Summary
Throughout this short introduction to React/Redux in WordPress we’ve seen all the ingredients necessary to create good UIs. In essence, we have seen that components must be pure functions that receive properties and generate HTML, how we can use stores to maintain the state of our app independently from the UI, and how we can integrate each other.
Extending React components so that they pull values from a store is as easy as using withSelect
and withDispatch
and generate a higher-order component that adds the required missing props.
Featured Image by Dmitry Nucky Thompson on Unsplash.
Leave a Reply