Problem
Let’s pretend I have the following:
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
}
}
And in that action creator, I want to access the global store state (all reducers). Is it better to do this:
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
or this:
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return (dispatch, getState) => {
const {items} = getState().otherReducer;
dispatch(anotherAction(items));
}
}
Asked by ffxsam
Solution #1
Whether or not accessing state in action creators is a good concept is a matter of debate:
If you discover that you require this, whichever of the ways you offered will enough. The first method does not necessitate the use of any middleware:
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
However, as you can see, it depends on store being a singleton exported from another module. We don’t advocate it because it makes adding server rendering to your app much more difficult because, in most circumstances, you’ll want to have a distinct store for each request on the server. While this method is theoretically valid, we do not suggest exporting a store from a module.
This is why we advise using the second method:
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return (dispatch, getState) => {
const {items} = getState().otherReducer;
dispatch(anotherAction(items));
}
}
It would necessitate the usage of Redux Thunk middleware, but it is functional on both the client and the server. More information regarding Redux Thunk and why it’s needed in this case can be found here.
Your actions should ideally not be “fat” and contain as little information as possible, but you should feel free to do whatever works best for you in your particular application. The Redux FAQ contains information on how to separate functionality across action creators and reducers, as well as when getState in an action creator could be useful.
Answered by Dan Abramov
Solution #2
When your circumstance is straightforward, you might make advantage of
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
However, your action maker may need to activate many actions at times.
As an example, an async request necessitates the use of ACTIONS REQUEST LOAD REQUEST LOAD SUCCESS REQUEST LOAD FAILURE REQUEST LOAD SUCCESS REQUEST LOAD FAILURE REQUEST LOAD SUCCESS
export const [REQUEST_LOAD, REQUEST_LOAD_SUCCESS, REQUEST_LOAD_FAIL] = [`REQUEST_LOAD`
`REQUEST_LOAD_SUCCESS`
`REQUEST_LOAD_FAIL`
]
export function someAction() {
return (dispatch, getState) => {
const {
items
} = getState().otherReducer;
dispatch({
type: REQUEST_LOAD,
loading: true
});
$.ajax('url', {
success: (data) => {
dispatch({
type: REQUEST_LOAD_SUCCESS,
loading: false,
data: data
});
},
error: (error) => {
dispatch({
type: REQUEST_LOAD_FAIL,
loading: false,
error: error
});
}
})
}
}
Note: you need redux-thunk to return function in action creator
Answered by Nour Sammour
Solution #3
@Bloomca is correct. It appears that passing the value needed from the store as an argument to the dispatch method is easier than exporting the store. Here’s an illustration:
import React from "react";
import {connect} from "react-redux";
import * as actions from '../actions';
class App extends React.Component {
handleClick(){
const data = this.props.someStateObject.data;
this.props.someDispatchFunction(data);
}
render(){
return (
<div>
<div onClick={ this.handleClick.bind(this)}>Click Me!</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return { someStateObject: state.someStateObject };
};
const mapDispatchToProps = (dispatch) => {
return {
someDispatchFunction:(data) => { dispatch(actions.someDispatchFunction(data))},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Answered by Jason Allshorn
Solution #4
I’d like to point out that reading from the store isn’t all bad — it might just be more convenient to decide what should be done based on the store rather than passing everything to the component and then as a function parameter. I absolutely agree with Dan that using store as a singletone should be avoided unless you are certain that you will solely use it for client-side rendering (otherwise hard to trace bugs might appear).
I recently constructed a library to deal with redux’s verbosity, and I think it’s an excellent idea to put everything in the middleware, so you can use dependency injection everywhere.
As a result, your example will be as follows:
import { createSyncTile } from 'redux-tiles';
const someTile = createSyncTile({
type: ['some', 'tile'],
fn: ({ params, selectors, getState }) => {
return {
data: params.data,
items: selectors.another.tile(getState())
};
},
});
However, as you can see, we don’t really modify data here, thus there’s a strong possibility we’ll be able to combine it somewhere else using this selection.
Answered by Bloomca
Solution #5
Presenting a different approach to this problem. Depending on your application, this may be better or worse than Dan’s answer.
By dividing the action into two independent functions, you can obtain the state from the reducers into the actions: first ask for the data, then act on the data. You may accomplish this by utilizing redux-loop.
First and first, ‘kindly request the data.’
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
}
}
Intercept the ask in the reducer and pass the data to the second stage action using redux-loop.
import { loop, Cmd } from 'redux-loop';
const initialState = { data: '' }
export default (state=initialState, action) => {
switch(action.type) {
case SOME_ACTION: {
return loop(state, Cmd.action(anotherAction(state.data))
}
}
}
Do anything you want now that you have the data.
export const ANOTHER_ACTION = 'ANOTHER_ACTION';
export function anotherAction(data) {
return {
type: ANOTHER_ACTION,
payload: data,
}
}
I hope this information is useful to someone.
Answered by Andrei Cioara
Post is based on https://stackoverflow.com/questions/35667249/accessing-redux-state-in-an-action-creator