Writing Actions and Reducers
┻┳|
┳┻| _
┻┳| •.•) 💬 "Hey, Checkout this awesome documentation for actions and reducers!"
┳┻|⊂ノ
┻┳|
What are actions?
Quoting the redux documentation they are:
Actions are payloads of information that send data from your application to your store.
They are simply plain JavaScript objects
1 2 3 4 5 6 7 |
|
They must have type property, typically a constant with a string value, but any other properties are optional
Why we use them
We need them to trigger changes to the application's store via reducers. To do that we use Action Creators
Action Creators
They are simply function that returns actions objects
1 2 3 4 5 6 7 8 9 10 11 |
|
Note: Stick to es6 import/export module system and when possible provide a default value for the parameters
These action creators are used in the connected components or in MapStore2 plugins But actions by themselves are not enough we need Reducers that intercepts those actions and change the state accordingly.
Note: Remember to put all the actions .js files in the web/client/actions folder or in js/actions if you are working with custom plugins
Reducers
Again quoting redux documentation they are:
Reducers specify how the application's state changes in response to actions sent to the store.
Reducers are pure functions that take the previous state and an action and return a new state
(previousState, action) => newState
let's see an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
As you can see we are changing the center of the map that triggers the panning action of the mapping library
And that's it we have wrote an action and a reducers that make the map panning around.
Note: Remember to put all the reducers .js files in the web/client/reducers folder or in js/reducers if you are working with custom plugins
Advanced usage and tips
Sometimes you need to change a value of an item which is stored inside an array or in a nested object.
Let's imagine we have this object in the store:
1 2 3 |
|
And we have created an action that holds the id of the object to change and some properties
1 2 |
|
Then in the reducer we can have different implementations. Here we show the one using arrayUpdate from @mapstore/utils/ImmutableUtils for updating objects in array
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Testing
Tests in mapstore are stored in __tests__
folder at the same level where actions/reducer are.
The file name is the same of the action/reducer with a '-test' suffix
1 2 3 4 5 |
|
We use expect as testing library, therefore we suggest to have a look there.
How to test an action
Typically you want to test the type and the params return from the action creator
let's test the mapTo action:
1 2 3 4 5 6 7 8 9 10 11 |
|
In order to speed up the unit test runner, you can:
- change the path in tests.webpack.js (custom/standard project) or build\tests.webpack.js (framework) to point to the folder parent of tests
for example '/js/actions'
for custom/standard project or '../web/client/actions'
for framework
- then run this command:
npm run continuoustest
This allows to run only the tests contained to the specified path. Note: When all tests are successfully passing remember to restore it to its original value.
How to test a reducer
Here things can become more complicated depending on your reducer but in general you want to test all cases
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Here for speedup testing you can again modify the tests.webpack.js (custom/standard project) or build\tests.webpack.js (framework)
in order to point to the reducers folder and then running
npm run continuoustest
Actions and epics
Actions are not only used by redux to update the store (through the reducers), but also for triggering side effects workflows managed by epics
For more details see Writing epics