Is Redux unidirectional? - reactjs

After implementing Flux, it was easy to see that it is in fact unidirectional.
Flux recap: The View takes in user actions, which get sent to and interpreted by Action Creators, which get sent to the Dispatcher, which get broadcast to the Stores, which eventually trigger an update back in the View.
With Redux, although I've only read a handful of blog posts on it, it seems as though the Action Creators are in fact returning the formatted action object back to the View that fired off the action in the first place.
See: https://code-cartoons.com/a-cartoon-intro-to-redux-3afb775501a6#.3hquuzljm
So the question is this: Does having the Action Creator by design return to the View disrupt the very notion of uni-directional workflow?
I haven't implemented Redux just yet, so perhaps I'm missing a step, but this sticks out to me as a big difference between Flux and Redux.

I think you're putting too much emphasis on what action creators are.
An action creator is literally just this:
function login(username, password) {
return { type: 'LOGIN', payload: { username, password };
}
These two things are identical:
class Component extends React.Component {
...
render() {
const { username, password } = this.props;
return (
...
dispatch({ type: 'LOGIN', payload: { username, password });
// or
dispatch(login(username, password));
...
);
}
}
And then if you user react-redux's connect, it can look like
class Component extends React.Component {
...
render() {
const { username, password } = this.props;
return (
...
login(username, password)); // connect binds the AC to dispatch for convenience.
...
);
}
}
Action creators are not a large abstraction. they're just a special name for a function that helps makes actions to keep your code DRY. They don't do anything to change the unidirectional model.

The data flow in Flux and Redux is pretty much the same, you just don't have the Dispatcher and callbacks, because the actions operate on store. (Compare it with this flux diagram.)
The Redux documentation has a great chapter on this topic:
Redux architecture revolves around a strict unidirectional data
flow.
This means that all data in an application follows the same lifecycle
pattern, making the logic of your app more predictable and easier to
understand. It also encourages data normalization, so that you don't
end up with multiple, independent copies of the same data that are
unaware of one another.
If you're still not convinced, read
Motivation and The Case for
Flux
for a compelling argument in favor of unidirectional data flow.
Although Redux is not exactly Flux, it
shares the same key benefits.
The data lifecycle in any Redux app follows these 4 steps:
You call store.dispatch(action).
The Redux store calls the reducer function you gave it.
The root reducer may combine the output of multiple reducers into a single state tree.
The Redux store saves the complete state tree returned by the root reducer.

Does having the Action Creator by design return to the View disrupt the very notion of uni-directional workflow?
TLDR:
The action creator in redux returns the action without calling dispatch. Correct.
Does this break unidirectional workflow? No.
After receiving the action from the action creator, it can be forwarded to the store by calling the dispatch() function with the returned action as parameter. Thus the data flow is still unidirectional.
Details:
1
In traditional Flux implementations, action creators often trigger a dispatch when invoked, like so:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
By contrast, in Redux action creators are pure functions with zero side-effects. They simply return an action:
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
This makes them more portable and easier to test. To actually initiate a dispatch, pass the result to the dispatch() function:
dispatch(addTodo(text))
dispatch(completeTodo(index))
http://rackt.org/redux/docs/basics/Actions.html
2
As shown in https://code-cartoons.com/a-cartoon-intro-to-redux-3afb775501a6#.e9br039va
The view requests an action. The action creator formats it and returns it.
The action is either dispatched automatically (if bindActionCreators() was used in setup), or the view dispatches the action.
The store receives the action.
So therefore the dataflow is still unidirectional.

Related

Is it mandatory to create action creator in redux layer?

I am new in redux library of react
This is my code
// action creator
export function updateCategories(payload) {
return { type: UPDATE_CATEGORY, payload };
}
// dispatch action creator
dispatch(updateCategories({ list: data }));
But instead if I do like :
dispatch({ type: UPDATE_CATEGORY, payload });
so what is problem if I write action directly in dispatch without returning from function?
Technically it's fine, you can dispatch straight from the component, but there's advantages of having actions creators, e.g.
It creates a intuitively named, reusable function for the dispatch, which you can import as needed, rather than manually dispatching all over the place. So if you want to change how the dispatch of a certain action works, you only have to change in the action creator and not go through all the places it's used and change each one
Simply dispatching something with a payload is fine, but you may also end up having logic to go along with that dispatch, like processing of the payload or fetching of data (using some tool like redux-thunk). It's better to have a single action creator where that's all defined that you can reuse throughout your application, rather than copy pasting that logic all over the place
It helps in code re-usability.
You can go through this link for more Info

What is the life cycle of a React component in context of Redux?

I'm trying to restructure my React app around Redux, and getting confused.
one site says:
Components receive props from their parent. These props should not be
modified inside the component.
another says:
You used to be able to change props with setProps and replaceProps but
these have been deprecated. During a component’s life cycle props
should not change (consider them immutable).
So I should consider props to be immutable over a component's lifetime. OK, then, the alternative is state (React state, which I understand is a very different thing from Redux state. OK...)
React state is the mutable state of the component. It belongs to the component and, unlike props, can change during the component's life cycle. OK. Outside of the context of Redux, I totally get that. Each component owns its own mutable state and passes what it needs to down to its children as props, which are for the children immutable. When the state changes it will cause the component to re-render its children, giving them new props as needed.
Now introduce Redux. The Redux store holds a single state for the entire app. Does this now replace any React state? Are all of the elements of the Redux state delivered to React components as props? There is mapStateToProps which seems to suggest this. So can I now forget about React state entirely?
I think of the component life cycle as lasting, say, as long as the user can see the thing on screen. But if props can't change during the component life cycle, and everything is now (from the React perspective) props - does that mean the life cycle is only as long as it takes Redux to refresh its store?
As pointed out by Dan Abramov in his famous You might not need redux article,
Redux should be used only when you need persistence across the application. When data is ephemeral (think about a selected accordion opened in a simple view) you can safely store your state in a local state.
So:
Does this now (Redux) replace any React state?
If you wish, yes. But it isn't mandatory.
Are all of the elements of the Redux state delivered to React components as props?
Usually, yes.
So can I now forget about React state entirely?
Yes, you can. Although is not mandatory and local/redux state can live happily together.
[...] does that mean the life cycle is only as long as it takes Redux to refresh its store?
Renders occurs as any state (local or redux) changes.
Lucy Bain's post is good as an explainer, but note that the mentions of setProps refer to a very old version of React, and the linked release notes for React 0.14 describe those as only having been useful for updating the top-level component in an app. Today, if you actually need to update the props for the root component, you'd call ReactDOM.render(<MyApp newProp={123} />) a second time.
See the Redux FAQ entry on splitting state between Redux and React components for some rules of thumb to help decide where each piece of state should live.
I'd also encourage you to read through the React-Redux documentation as well to understand how they fit together.
I think what you need to understand first is the Redux cycle which goes like this:
Action Creator->Action->dispatch->Reducers->State
An Action Creator is a function that will return a plain JavaScript object referred to as the Action. The action will have a type and payload that provides context on what its doing, for example, creating an insurance policy, it would look like so:
// People dropping off a form (Action Creator)
const createPolicy = (name, amount) => {
return { // Action(a form in this analogy)
type: 'CREATE_POLICY',
payload: {
name: name,
amount: amount
}
};
};
All action creators look identical to what you see what here with some small variation.
But I know the question is understanding the cycle and their purposes not so much the syntax.
So you want to understand what role your action creators need to play in your React app and then on to your Reducers and figuring out their role, but really after you've figured out the hard part, the Action Creators, the rest start to fall into place.
The dispatch receives the action and dispatches it out to all the different Reducers. dispatch is part of the Redux library itself, so you don't need to write it out and your question regarding mapStateToProps if you tie it in with the higher order component utilizing the connect() helper, that whole process is like a manual override of the dispatch process.
The idea behind Reducers is that we write out functions and each one models a different behavior inside the application. Each reducer gets called with an Action, the reducer inspects the action and determines whether to modify behavior based on that action.
So action creators are like people filing an insurance claim and the action is the actual claim. Those claims go to these different departments called reducers.
So keeping to this analogy of insurance claims, a reducer I may want to create would be a claims history reducer like so:
// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {
};
So the reducers' job is to determine whether or not it cares about the type of action it is receiving. If it is of type createClaim then we want to ensure the code inside the function pulls off the payload property and add it to the list of claims, if not then return list of claims unchanged and that would look like so:
// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {
if(action.type === 'CREATE_CLAIM') {
// we care about the action (claim)
return [...oldListOfClaims, action.payload]
}
// we dont care about the action (form)
};
So I am just using ES2015 syntax which takes an array, take all of the records and add them to a brand new array and add the new record of action.payload.
Its the equivalent to doing const numbers = [1,2,3] and then [...numbers, 4] which outputs:
(4) [1, 2, 3, 4]
Or the equivalent of oldListOfClaims.push(action.payload); but there is a distinct difference between this one and the one I used.
In the syntax I used for the reducer I am creating a brand new array and adding records to it, whereas the push() method is modifying an existing array.
We always want to avoid modifying existing data structures inside a reducer. You will never see push() inside a reducer.
Then there is the case where we don't care about the action:
// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {
if(action.type === 'CREATE_CLAIM') {
// we care about the action (claim)
return [...oldListOfClaims, action.payload]
}
// we dont care about the action (form)
return oldListOfClaims;
};
Next, you need to handle the case where the very first time a reducer gets called, there will be no data to passed to it. We will essentially receive the value of undefined. We need to default the value of the first argument.
// Reducers (Departments)
const claimsHistory = (oldListOfClaims = [], action) => {
if(action.type === 'CREATE_CLAIM') {
// we care about the action (claim)
return [...oldListOfClaims, action.payload]
}
// we dont care about the action (form)
return oldListOfClaims;
};
So undefined got replaced with an empty array.
So figuring out your actions and reducers is the hard part when implementing Redux as well as the fine grain rules that go with it such as making sure you don't modify the array that gets passed in and ensuring you always return some value.
The overall goal of a reducer is to take some existing data passed to it as an action and find and return that existing data based upon the contents of an action.
So this is all the baseline stuff to get you started. Out of all this is where you want to return a new instance of a Redux store.
Depending on your project you may have 1 to 3 or more action creators and reducers. You then wire all these up into a single object called a store which is just an assembly of different actions and reducers.
So somewhere in your components you are going to be adding something like this: const { createStore, combineReducer } = Redux;
This is what your combineReducers looks like:
const ourDepartments = combineReducers({
accounting: accounting,
claimsHistory: claimsHistory,
policies: policies
});
Then you complete creating your store like so:
const store = createStore(ourDepartments);
store;
The store represents the entire Redux application. It contains references to all your different reducers and to all your state produced by those reducers or data.
The store object has some useful functions such as the dispatch function. In order to call dispatch() we have to pass in an action created by an action creator and then pass it off to store.dispatch().
const store = createStore(ourDepartments);
const action = createPolicy('Alejandra', 35);
console.log(action);
store.dispatch();
When you console log out action you should see you have the type of action and your payload:
{type: "CREATE_POLICY", payload: {…}}
You then take that action and pass it to store.dispatch() like so:
So far you probably saw an error saying that Action must be a plain JavaScript object and so on, well this error will go away once you pass in the action like so:
store.dispatch(action);
You can check to see the state of the application print out like so:
console.log(store.getState());
{accounting: 135, claimsHistory: Array(0), policies: Array(1)}
accounting: 135
claimsHistory: []
policies: ["Alejandra"]
proto: Object
Now you can start passing in the actions like so:
store.dispatch(createPolicy('Alejandra', 35));
store.dispatch(createPolicy('Ben', 20));
store.dispatch(createPolicy('Daniel', 78));
store.dispatch(createClaim('Alejandra', 120));
store.dispatch(createClaim('Ben', 50));
store.dispatch(deletePolicy('Daniel'));
console.log(store.getState());
Output in console:
{accounting: 63, claimsHistory: Array(2), policies: Array(2)}
accounting: 63 claimsHistory: Array(2) 0: {name: "Alejandra",
amountOfMoneyToCollect: 120} 1: {name: "Ben", amountOfMoneyToCollect:
50} length: 2
proto: Array(0) policies: Array(2) 0: "Alejandra" 1: "Ben" length: 2
proto: Array(0)
proto: Object
So thats how the Redux library works
Alright, so I showed you how it works on its own, but how do the two libraries, Redux and React interact with each other?
So yes, with the implementation of Redux, we make use of component level state, much less frequently. We generally store all of our data inside of Redux instead.
There are some scenarios where we want to have state inside of both Redux and React components, but in general all your state inside of React app is now inside of Redux instead, so that translates into a much more simple React application.
Lets say you had some iTunes type of app, how would we put it together with just Reactjs?
So this would be your app without redux:
So here your SongDetail only needs to know what your currently selected song is. So your App component passes it down to SongDetail as a prop and the SongDetail would render it out to the screen.
With React alone this would be a simple and straightforward application.
So how does your application change with Redux?
So just as before, we are going to have an App component, a SongList and SongDetail, but the App component is going to be passing down very little information down the SongList and SongDetail.
Instead, we are going to abstract out these ideas of creating a list of songs and selecting a song and what the currently selected song is into a redux application.
So you would have a reducer that will produce a list of songs and a reducer that records what a currently selected song is. Those are the two pieces of state in your application.
Finally, we are going to ensure we have an action creator to somehow change your state. That is the only way you change your state inside a redux app.
So your action creator may be called select song, that will dispatch an action and tell the selected song reducer to update its data and reflect the new currently selected song.
So thats your app with Redux.

What is the difference between using redux-thunk and calling dispatch() directly

I'm in the learning phase of understanding redux state management and still trying to negotiate the bewildering jungle of boilerplate code and middleware, much of which I'm taking on faith as 'good medicine'. So I hope you'll bear with me on this perhaps rudimentary question.
I know that redux-thunk allows action creators to proceed asynchronously and dispatch a regular action at a subsequent time. For example, I can define a thunk action creator in my actions.js:
export function startTracking() {
return (dispatch => {
someAsyncFunction().then(result => dispatch({
type: types.SET_TRACKING,
location: result
}))
})
}
And invoke it from within a React component like so:
onPress={() => this.props.dispatch(actions.startTracking())}
My question is, what advantage does the above code confer over simply dispatching an action from inside an asynchronous callback?
import { store } from '../setupRedux'
...
export function startTracking() {
someAsyncFunction().then(result => {
store.dispatch({
type: types.SET_TRACKING,
location: result
})
})
}
which I would invoke inside my component
onPress={() => actions.startTracking()}
or even
onPress={actions.startTracking}
Is there anything problematic with accessing store directly via an import as I'm doing in the 2nd example?
There is nothing wrong doing so. From the redux-thunk page:
If you’re not sure whether you need it, you probably don’t.
The creator of redux explain the advantage of using it here:
This looks simpler but we don’t recommend this approach. The main reason we dislike it is because it forces store to be a singleton. This makes it very hard to implement server rendering. On the server, you will want each request to have its own store, so that different users get different preloaded data.
Basically, using redux-thunk will save you the store import in each action creator file and you will be able to have multiple store. This approach also give you the opportunity to write a little bit less code and to avoid spaghetti code. Many redux developer don't like to import the store and to manually dispatch because it can create circular dependencies if the code is badly separated (importing an action name from the action creator file in the reducers file and importing the store from the reducers file in the action creator file). Also, dispatching directly an action like that might break the middleware workflow, ie: the action might not be handled by a middleware.
But honestly, if you don't see an advantage to it yet, don't use it. If one day you have trouble with async actions, redux-thunk might be the answer.

How to update store state in react-redux?

I'm working on a component in React (with Redux) that has the requirements to:
Retreive data from an API endpoint.
Display that data, with one field being editable.
If the editable field is edited, it has to update the rest of the fields and send them to a different endpoint.
I'm having trouble grasping how exactly I should implement the editing using the Redux metodology.
Here is a simplified component:
class MyComponent extends Component {
constructor(...args) {
super(...args);
this.props.dispatch(getDataFromEndpoint());
}
editField(e) {
this.props.dispatch(editFieldAction(e.target.value));
}
render() {
return (
<div>
<input type="text" defaultValue={this.props.data.editableField} onChange={this.editField} />
{
this.props.data.uneditable.map(x => {
return (
<span>{x}</span>
);
})
}
</div>
);
}
}
const mapProps = state => {
const { data } = state.endpointData;
return { data };
}
export default connect(mapProps)(MyComponent);
Note that I've written this component as an example, it might have errors, but you should get the point. Whenever this.editField is called, it should update every value in this.props.data.uneditable.
What is the correct way to do this?
In a sense these questions all boil down to: How do I wire up my component(s) to read from (and write to) Redux state. This is essentially the purpose of redux-react's connect function (which you have in the bottom of your example). You use the first parameter, mapStateToProps, to be able to read from state. You use the second parameter (that you don't have yet) - mapDispatchToProps - to provide the means to write to it. Dispatching an action is how you update Redux state.
You can simply use this.props.dispatch, but it is more idiomatic to use mapDispatchToProps, which simply provides an object where each property is a function which calls dispatch with the appropriate action creator. You might accept as a parameter for example the data which you are looking to update your store with.
What ends up happening is in your component when you want to update the state (say from an input), you use the methods you wired up with mapDispatchToProps to dispatch an action with the relevant data (the updated input value), and then write a reducer which responds to the action and updates the relevant part of your store. Redux will then trigger a re-render in your component and it will pull the updated data from the store.
Async actions are handled a bit differently of course (which is what your API calls will be), because they typically have several changes to state being spread out over time. Usually something like:
Start the API request. (Dispatch an action to..) Set a flag somewhere in your state indicating the API request is 'in transit'.
Receive the response. (Dispatch again to..) Set a flag somewhere saying the request is finished, and if it was successful, store your response data somewhere. If it was an error, store the error (or just the fact there was an error).
I would recommend redux-thunk for this purpose, since at least for me it is the easiest to understand and work with out of all the various libraries and methods to handle async with redux. Instead of dispatching an object which contains the data describing the action, you instead dispatch a function, which means you can write any kind of logic you would like, allowing you to dispatch several times for example. This makes it easy to do the steps outlined above.. simply have a function which calls your API, and in the callback (or .then() method) you dispatch an action with the result.

Redux action creators state access best practices

In redux, when we need to access a state property that is not directly related to a componentProps but is triggered from this component (ie: a grand parent component id that is stored in the state) should we try to pass this part of the state to action creators from the component that triggers the event ie:
onClick={() => doSomething(grandParentId)}
----
function doSomething(grandParentId) {
console.log(grandParentId)
}
or should we get the data from getState with redux-thunk?
onClick={doSomething}
----
function doSomething() {
return (dispatch, getState) => {
console.log(getState().grandParentId)
}
}
I know that the answer sounds like the first approach is more proper, but I somehow feel that getState with redux-thunk can lead to bad practices and I would like to know when I should use it or not.
If you already have that information in your component, I don't see why not passing it along to your action creator. The flow of data is much easier to follow this way, in my opinion.
I would take advantage of getState() only when I need to access part of the state tree that I wasn't able to pass via action creator.
If the data is already in the redux state, then I would access it with getState. Fewer arguments being passed around makes it simpler IMO.

Resources