Professional Documents
Culture Documents
State management is the philosophy that we choose to make sure that our state remain clear and
traceable over the time during the presence of the application on the browser while reading and
writing into it.
Simply said, State management maintains and stores the information of any user till the end of the
user session.
Problem of props
So we all know that React is a great library :
• It follows a component based architecture,
• It encourages lifting state up,
• It break up your UI into small components and
• It pass data from top to bottom using props.
This a good approach to build UI as it facilitates better code reuse and it makes your app more
predictable and easier to test. However there’s a caveat to that.
When you’re passing data through props from top to bottom of the component tree, you probably
experienced this frustration where you want to pass data from the top level component to a 3rd or
4th level component but you end up passing these data to components on each level of the tree.
This is what we call Prop-drilling!
If the desktop was a React application, we could store all of these data in the state of our app.
Think about the React Global State as a JavaScript object containing all the necessary
information needed for our application view.
The state management is to maintain and store the information of the user till the session ends True
The store is :State which is global and shared between component
Props drilling refers to the process of passing the props through the component tree to deliver data
to certain component True
What is Redux?
Redux is a predictable state container for JavaScript apps.
It helps us write applications that behave consistently, run in different environments (client, server,
and native), and it is easy to test.
On top of that, it provides a great developer experience, such as live code editing combined with a
time traveling debugger.
We can use Redux together with React, or with any other view library.
Redux is lightweight library (about 2kB, including dependencies)
The State
If you are not sure what this state means, let’s replace it with a more generic term: data.
State is data that change from time to time. State determines what’s displayed on the user interface.
Let’s say we are building a Dribbble shot page. What is the data we want to display on the page?
They include the author’s profile photo, name, the animated GIF, the number of hearts, the
comments, and so on.
Steps:
First, we need to fetch all these data from a server in the cloud and put it somewhere. Next, we need
to actually display the data. We need to assign pieces of this data to corresponding UI elements that
represent what we actually see in the browser. For example, we assign the URL of the profile photo
to the src attribute of an HTML img tag:
<img src='https://url/to/profile_photo'>
Finally, we need to handle changes to the data. For example, if a user adds a new comment to a
Dribbble shot -or adds a star- we need to update the view accordingly.
Coordinating these three aspects of state is a big part in front-end development, and React has
various degree of support for this task. Sometimes the built-in facility in React works well enough.
But as the app grows more complex, its state may become harder to manage with React alone.
That’s why Redux is created
Aspect of data management:
In general, there are three aspects of data that we need to manage in an app:
1.Changing data
Redux allows us to divide and conquer. It provides a standard way to break data updating logic into
small “reducers”. Those reducers work harmoniously together to complete a complex action.
The store
with Redux, we fetch data once and store it in a central place, conveniently called store.
The data is then ready for use anytime by any component. This is not unlike having a superstore
nearby where our chefs can buy all the ingredients. The superstore sends trucks to carry back
vegetables and meats in bulk from farms. It’s a lot more efficient than asking individual chefs to go
to the farms themselves!
The store also serves as the single source of truth. Components always retrieve data from the store,
not from anywhere else. This keeps all the UI content consistent.
This approach is more efficient than the naive way of fetching data from every component. We
could fetch data once and located in the store
Redux allows us to divide and conquer. It provides a standard way to break data updating logic into
small reducers(we will learn more about Reducers later in this course). Those reducers work
harmoniously together to complete a complex action.
What's Action?
An action is like a message that we send (i.e. dispatch) to our central Redux store. We can think of it
as a description of what it should happen. It can literally be anything. But ideally we want to stick to
an agreed-upon pattern. And the standard pattern is as follows:
const Action = {
type: string; // Actions MUST have a type
payload?: any; // Actions MAY have a payload
error?: boolean; // Actions MAY have an error field
// when true, payload SHOULD contain an Error
};
What ‘s Reducer?
Reducers specify how the application's state changes in response to actions sent to the store.
Remember that actions only describe what happened, but don't describe how the application's state
changes. That’s the reducer job.
Example of a reducer.
const reducer = (state, action) => {
switch (action.type) {
case type1:
return; // the new state
return; // the new state
default:
return state;
}
What’s Store?
We defined the actions that represent the facts about “what happened” and the reducers that are on
charge of updating the state according to those actions.
The Store is the object that brings them together. The store has the following responsibilities:
• Holds application state;
• Allows access to state via getState();
• Allows state to be updated via dispatch(action);
• Registers listeners via subscribe(listener);
• Handles unregistering of listeners via the function returned by subscribe(listener).
Redux data flow
The image below describes the redux data flow and how every part get fired :
Redux vs react-redux
Redux gives you a store, and lets you keep state in it, and get state out, and responds when the state
changes. But that’s all it does.
It’s actually react-redux that lets you connect pieces of the state to React components.
That’s right: redux knows nothing about React at all.
These libraries are like two peas in a pod, though. 99.999% of the time, when anyone mentions
“Redux” in the context of React, they are referring to both of these libraries in tandem. So that keep
in mind, when you see Redux mentioned on StackOverflow, or Reddit, or elsewhere.
The redux library can be used outside of a React app too. It’ll work with Vue, Angular, and even
backend Node/Express apps.
To use redux, we need Redux
To use redux with react, we need Reduxreact -redux
To install react-redux, we run npm i react-reduxnpm install --save react-redux
Example:
In this example, the Counter component holds the state, and the App surrounding it is a simple
wrapper.
//---------------Counter.js-------------
import React, { useState } from "react";
createStore:
Redux comes with a handy function that creates stores, and it’s called createStore.
Let’s create our store in the index.js. Import createStore and call it like so:
//----- index.js -------
import React from "react";
import { render } from "react-dom";
import Counter from "./Counter";
import { createStore } from "redux";
import "./index.css";
Reducer:
Redux reducer is basically a fancy version of Array’s reduce. Earlier, we saw how Redux reducers
have this signature:
(state, action) => newState
Meaning: it takes the current state, and an action, and returns the newState. Looks a lot like the
signature of an Array.reduce reducer!
Redux reducers work just like the function you pass to Array.reduce! The thing they reduce is
actions. They reduce a set of actions (over time) into a single state. The difference is that with array
reduce it happens all at once, and with Redux, it happens over the lifetime of your running app.
const initialState = {
count: 0
};
What is an action?
Actions are very free-form things. As long as it’s an object with a type it’s fair game.
In order to keep things sane and maintainable, we Redux users usually give our actions types that
are plain strings, and often uppercased, to signify that they’re meant to be constant values.
An action object describes a change you want to make (like “please increment the counter”) or an
event that happened (like “the request to the server failed with this error”).
Actions, despite their active-sounding name, are boring, inert objects. They don’t really do
anything. Not on their own, anyway.
In order to make an action DO something, you need to dispatch it.
switch(action.type) {
case 'INCREMENT':
return {
count: state.count + 1
};
case 'DECREMENT':
return {
count: state.count - 1
};
case 'RESET':
return {
count: 0
};
default:
return state;
}
}
………..
The result:
Hey look at that! The count is changing! We’re about ready to hook this up to React
What is a Redux action ?A plain object
What function use to trigger an action in Redux ?dispatch()
An action should always contain a type
// With this:
export default connect(mapStateToProps)(Counter);
Redux provides a standard way to break data updating logic into small reducers. Those reducers
work harmoniously together to complete a complex action.
Dispatch Redux Actions from a React
Component:
By now the counter is connected, we received the count value as a props. The next step is to make
respond to the action ‘INCREMENT’ and ‘DECREMENT’. To make it possible the Redux library
in addition to mapped state, it also passes a function called dispatch to let us trigger the action. If
you check the console you will find that our store state count value change when we dispatch an
action.
const Counter = props => {
console.log(props);
const increment = () => {
props.dispatch({ type: "INCREMENT" });
};
return (
<div className="counter">
<h2>Counter</h2>
<div>
<button onClick={() => decrement()}>-</button>
<span className="count">{props.count}</span>
<button onClick={() => increment()}>+</button>
</div>
</div>
);
};
const mapStateToProps = state => {
return {
count: state.count
};
};
Hint : wrapp the entire app with the Provider component import {
Provider
} from "react-redux"; const store =
createStore
(reducer); const App = () => ( <
Provider
store={
store
}> <Counter />
</Provider>
);
Benefits of middleware
What is Middleware?
Redux middlewares work between Action Creators and Reducer. The Middleware intercepts the
action object before Reducer receives it and gives the functionality to perform additional actions or
any enhancements with respect to the action dispatched.
Benefits of middleware
Why use it?
The action/reducer pattern is very clean for updating the state within an application. But what if we
need to communicate with an external API? Or what if we want to log all of the actions that are
dispatched? We need a way to run side effects without disrupting our action/reducer flow.
Middleware allows for side effects to be run without blocking state updates.
We can run side effects (like API requests) in response to a specific action, or in response to every
action that is dispatched (like logging). There can be numerous middleware that an action runs
through before ending in a reducer.
Benefits of middleware
The redux middleware syntax is a mouthful: a middleware function is a function that returns a
function that returns a function.
The first function takes the store as a parameter, the second takes a next function as a
parameter, and the third takes the action dispatched as a parameter.
The store and action parameters are the current redux store and the action dispatched,
respectively. The real magic is the next() function.
The next() function is what you call to say "this middleware is done executing, pass this action to
the next middleware". In other words, middleware can be asynchronous
const reduxMiddleware = store => next => action => {
. . . . . .
next(action);
};
Logging action
Logging: One of the benefits of Redux is that it makes state changes predictable and transparent.
Every time an action is dispatched, the new state is computed and saved. The state cannot change
by itself, it can only change as a consequence of a specific action.
Wouldn't it be nice if we logged every action that happens in the app, together with the state
computed after it? When something goes wrong, we can look back at our log, and figure out which
action corrupted the state.
You already know this pattern. You just don’t call it “thunk.” If you want to execute the “do stuff
now” part, you have to call it like wrapper_function()() – calling it twice, basically.
Redux thunk:
Since it’s kind of annoying to write those objects by hand all the time (not to mention error-prone),
Redux has the concept of “action creators” to stamp these things out:
function userLoggedIn() {
return {
type: "USER_LOGGED_IN",
username: "dave"
};
}
It’s the same exact action, but now you can “create” it by calling the userLoggedIn function. This
just adds one layer of abstraction.
Instead of writing the action object yourself, you call the function, which returns the object. If you
need to dispatch the same action in multiple places around your app, writing action creators will
make your job easier.
Redux thunk:
Actually redux action does nothing. They are nothing but objects. To make them achieve a concrete
action (Calling an API, trigger another function …) we have to make that code lives inside a
function. This function (also called the thunk) is a bundle of work to be done. Right now our action
creator is performing an action. Like it’s shown in the example below
function getUser() {
return function() {
return fetch("/current_user");
};
}
Redux thunk:
If only there were some way to teach Redux how to deal with functions as actions.
Well, this is exactly what redux-thunk does: it is a middleware that looks at every action that passes
through the system, and if it’s a function, it calls that function. That’s all it does.
The only thing I left out of that little code snippet is that Redux will pass two arguments to thunk
functions:
Dispatch, so that they can dispatch new actions if they need to;
And getState, so they can access the current state.
Here’s an example to illustrate it:
function logOutUser() {
return function(dispatch, getState) {
return axios.post("/logout").then(function() {
// pretend we declared an action creator
// called 'userLoggedOut', and now we can dispatch it
dispatch(userLoggedOut());
});
};
}
the getState function can be useful for deciding whether to fetch new data, or return a cached
result, depending on the current state.
Redux thunk:
Set up redux-thunk in your project
If you have a project that already has Redux set up, adding redux-thunk is two steps.
First, install the package.
npm install --save redux-thunk
Then, wherever you have your Redux setup code, you need to import redux-thunk and insert its
middleware into Redux:
// You probably already import createStore from 'redux'
// You'll need to also import applyMiddleware
import { createStore, applyMiddleware } from "redux";
Just make sure you wrap thunk in the applyMiddleware call, or it won’t work.
After this, you’re all set: you can now dispatch functions that do whatever you need.
The basic definition of a thunk is that is a function that return another another functionTrue
Can we do an API call from a reducerFalse
To install redux thunk, we need to run:
npm install --save redux-thunk
npm i redux-thunk
It will be called with the entire state of the Redux store as the only argument.
It will be executed each time the function component is rendered (unless its reference has not
changed since a previous rendering of the component, so that’s result a set of cache can be returned
by the hook without re-executing the selector).
useSelector() also subscribes to the Redux store and runs our selector each time an action is sent.
With mapStateToProps, all individual fields were returned in a combined object. It didn't
matter if the return object was a new reference or not - connect () just compared the individual
fields. With useSelector(), returning a new object every time will always force a re-render by
default. If you want to retrieve multiple values from the store.
When using useSelector with an inline selector, a new instance of the selector is created
whenever the component is rendered.
This works as long as the selector does not maintain any state. However, memoizing selectors (e.g.
created via useSelector() from reselect) have internal state, and therefore care must be taken
when using them.
When the selector does only depend on the state, ensure that it is declared outside of the component
so that the same selector instance is used for each render.
useSelector(): exemple
Example :in the example below we are going to use the createSelector nad useSelector.
import React from "react";
import { useSelector } from "react-redux";
import { createSelector } from "reselect";
useDispatch()
mapDispatchToProps: This function is replaced by “useDispatch” function. This function returns
a reference to the dispatch function from the Redux store. We may use it to dispatch actions as
needed.
import React from "react";
import { useDispatch } from "react-redux";
return (
<div>
<span>{value}</span>
<button onClick={() => dispatch({ type: "increment-counter" })}>
Increment counter
</button>
</div>
);
};
useCallback()
Pass an inline callback and an array of dependencies. useCallback will return a memoized
version of the callback that only changes if one of the dependencies has changed.
This is useful when passing callbacks to optimized child components that rely on reference equality
to prevent unnecessary renders.
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Custom context
The <Provider> component allows us to specify an alternate context via the context prop. This is
useful if we’re building a complex reusable component, and we don't want our store to collide with
any Redux store our consumers' applications might use.
To access an alternate context via the hooks API, use the hook creator functions:
import React from "react";
import {
Provider,
createStoreHook,
createDispatchHook,
createSelectorHook
} from "react-redux";
const MyContext = React.createContext(null);
// Export your custom hooks if you wish to use them in other files.
export const useStore = createStoreHook(MyContext);
export const useDispatch = createDispatchHook(MyContext);
export const useSelector = createSelectorHook(MyContext);