Best practices for redux action creators - reactjs

What is the best practice around redux action creator when it comes to calling action creators for 2 different events for a same functionality? Using redux-thunk to dispatch the actions.
E.g. Lets say I have to write an action creator for saving and printing the user name. Which action creator is better between the 2 below and why?
Action Creator 1
export function actionCreator1(actionType)
{
switch(actionType)
{
case "save":
// dispatch
case "print":
// dispach
default:
}
}
Action Creator 2
export function actionCreatorSave()
{
// dispatch
}
export function actionCreatorPrint()
{
// dispatch
}

Both are wrong. In redux, action creators don't dispatch actions. They return actions that you dispatch (in React this is preferably within react-redux mapDispatchToProps function).
http://redux.js.org/docs/basics/Actions.html#action-creators
mentions this as opposite to flux.
(the exception being async actions)

Related

How action and reducers are connected with each other in react redux

I am new to react and redux. I have gone through many online tutorials on react redux but still not able to understand how action and reducer is connected. If I am right, we import action in container/component, we import reducer in a file where we create a store. So there is a connection between container - action, and there is a connection between reducer and store but in action file we dont import reducer. So how action is connected to reducer. I know that we have a type of action which will be checked in switch case in reducer. But how does it get passed to reducer.
Very High Level Overview
Action - Actions can update state
{ type: ACTION_TYPE, somePayload: payload }
The redux store exposes out a dispatch function, that ultimately wraps an action creator.
mapDispatchToProps = dispatch => {
return {
someWrappedAction: () => dispatch(actionCreatorFn()),
someOtherWrappedAction: val => dispatch(otherActionCreatorFn(val)),
}
}
useDispatch Hook returns the dispatch and you wrap action yourself
const dispatch = useDispatch()
<button onClick={() => dispatch(someActionCreatorFn())}>
Do Action
</button>
Reducer
The reducers form a state tree, starting with the root reducer passed to the redux store. The "connection" is made (conventionally) via the mapDispatchToProps and connect HOC. (Now can get the dispatch from useDispatch hook)
Reducers are pure functions that take two arguments, current state and an action, and returns the next state.
(currentState, action) => nextState
So how is each dispatch in mapDispatchToProps connected to the appropriate reducer...
When you dispatch an action creator it passes the action object to the root reducer. The action object is passed through the entire state tree and any reducers that process the action type consume it.
TLDR: dispatch function takes action as an argument and calls currentReducer(..., action).
When you call creteStore(reducer), the returned object contains dispatch and subscribe functions.
When you (or react-redux library) call subscribe(listener), redux will remember your listener function (in case of React, the listener has to make sure the component re-renders with new props, context, state, or refs - depending on concrete implementation).
When dispatching an action with dispatch(action), the dispatch function will call reducer(action, state), modify redux internal currentState then call each listener().

how to call a redux saga generator function?

maybe im missing the point or how sagas work but I'm not sure how to do the following
export default function* (){
yield all([
takeLatest(TOGGLE_MODAL, toggleModal)
]);
}
I have this "initial" function and inside here I call other functions.
one of the functions I call is a generator function and it works correctly
function* myOtherFunction(){
}
say I want to call this function elsewhere in my code, how would I do it?
I want to call it inside an action creator
(it HAS to be a generator as I'm using yield inside it)
You don't call Sagas directly.
You create actions through action creators, which you then dispatch to the store.
You register your sagas in the saga middleware on your store, so they get called each time a specific action is received.
Let's say you have an action CALL_OTHER_FUNCTION and the corresponding action creator callOtherFunction(). you dispatch it somewhere, for example in an component with mapDispatchToProps:
const mapDispatchToProps = dispatch => {
return {
callOtherFn: () => dispatch(callOtherFunction())
};
};
In your saga, you now just have to listen to this action with take(), takeAll(), takeLatest() or another effect creator that suits your needs.
export default function* (){
yield all([
takeLatest(TOGGLE_MODAL, toggleModal),
takeLatest(CALL_OTHER_FUNCTION, myOtherFunction]);
}
after that, your myOtherFunction generator is called on each action you dispatch to the store.

Dispatch in react redux

I am new to react and redux xo my questions will sound basic.
What does dispatch means? I am referring to the term dispatching an action.
Why do we need mapDispatchToProps to store actions on redux? We can simply import an action and use it. I have a scenario in which I have to load data when a component is mounted.
#mariazahid mapDispatchToProps will bind the action to your component so that you can pass it down to your presentation components. This is a pattern that is normally used within using Redux with React.
You can import your action and just dispatch the action, but in most scenarios a container -> component pattern is used. A container is where the actions are mapped to and the state and the only goal of this component is to pass this data down to components that are used for presenting that data.
When working in teams, it's a pattern that is easily adoptable. Instead of importing actions from left right and center, you will just have to be aware of the container and how it passes the required actions/data down to the children.
From an implementation perspective, dispatch is just a method that is used to communicate with your reducers
Let say that your action looks something like this
function myAction() {
return { type: 'MY_ACTION' };
}
You're trying to communicate with the reducer that responds to the action type 'MY_ACTION'
In your mapDispatchToProps you'd typically do something like this;
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(myActions, dispatch) }
}
Effectively, you're wrapping(binding) your actions to the dispatch method;
function bindActionCreators(actions, dispatch) {
// this is a very trivial implementation of what bindActionCreators does
let wrappedActions = {};
Object.keys(actions).forEach(action =>
// for every action, return a function that calls dispatch on the result of what your action returns
return function(...args) {
// remember here that dispatch is the only way you can communicate with the reducers and you're action's type will determine which reducer responds to return the new state
return dispatch(actions[action](..args));
}
);
}
And so, these "bound" actions are now assigned to a props.actions in your component.

Getting Redux State in action creators without Redux-Thunk middleware

Hi I am building a React/Redux app and wanted to get state values inside action creators. I can get state using Redux-Thunk middle ware like this
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return (dispatch, getState) => {
const {items} = getState().otherReducer;
dispatch(anotherAction(items));
}
}
I found some code on stackoverflow to import store in action creators, but somehow I need to know how to import store in action creators.
Is there a way to get state in action creators without using middle ware?

redux pre-binding through bindActionCreators, an anti-pattern?

Throughout my redux App, I frequently finding myself using the following pattern
// declare an action creator in a centralized / state management related location in the App (i.e. not the components/containers)
const myActionCreator1 = () => (dispatch) => { ... }
const myActionCreator2 = createAction(ACTION_2)
// then later in a mapDispatchToProps of a Container component
function mapDispatchToProps(dispatch) {
bindActionCreators({myActionCreator1, myActionCreator2}, dispatch);
}
Is these cases, is it an anti-pattern to pre-bind the action creators? given that there is only 1 dispatcher in redux working against 1 store?
i.e.
// actionCreators.ts
export const myActionCreators = {
myActionCreator: bindActionCreators(..., dispatch)
}
If this is pattern has no downside that would be good news for conciseness ....
Clarification
the conciseness benefit will only be apparent when multiple components re-use the same action creator. As these components will no longer require a mapDispatchToProps for straight-forward cases like the examples above
The connect function supports an "object shorthand" syntax for the second argument. Instead of creating a mapDispatchToProps function that receives dispatch (and probably uses bindActionCreators inside), you can just pass an object full of action creators directly to connect:
const actionCreators = {
addTodo,
toggleTodo
};
export default connect(null, actionCreators)(MyComponent);
That object full of action creators will be automatically run through bindActionCreators, and calling this.props.addTodo("Buy Milk") will dispatch the action creator appropriately.
I discussed some of the advantages of this approach in my blog post Idiomatic Redux: Why use action creators?.

Resources