preface
Why not use Redux
In a nutshell, Redux is too cumbersome to use:
- More suitable for medium and large projects
- The process of adding a global state is cumbersome and error-prone
- when
Redux
As the state tree grows, maintenance becomes more difficult
React Hook find out
Since React Hook was released, people have come up with the idea of using useContext and useReducer to simulate Redux
What are the benefits:
- You can and
Redux
For separate use, you only need to add state where it is used, which is equivalent to a local global state. - Ideal for small projects or individual study
React
The development of - Don’t write too much code, easy follow-up maintenance
UseContext and useReducer
useContext
So before we use useContext, we need to know what Context is, and it’s in the documentation, right
Context is designed to share data that is “global” to a component tree, such as the currently authenticated user, topic, or preferred language.
In other words, it is best to use Context to manage our “global” state.
UseContext is there to receive the context object and return the value of the context. In plain English, we can access the global state Context through useContext.
useReducer
Let’s look at the useReducer functions first.
const [state, dispatch] = useReducer(reducer, initialArg, init);
Copy the code
It receives a Reducer like (state, action) => newState and returns the current state and the expected accompanying Dispath method. (You’ll be familiar with Redux) official documentation
Began to practice
Let’s use a simple example to implement Redux using useContext and useReducer.
This example uses an implementation theme color switch to manage global state
Initialize the project
You can create a React project to test using create-react-app or simulate it in CodeSandbox
I write my projects in TypeScript, and you can do the same
NPX create-react-app my-app --typescript# orYarn create react-app my-app --typescriptCopy the code
Create a TypeScript React project
Create two child components
After the project is created, create a new Pages in the SRC directory
Pages creates two components, switch and Theme, respectively. Only the main directory structure is listed here
. ├ ─ ─ the SRC | └ ─ ─ pages | | ├ ─ ─ the switch | | | └ ─ ─ index. The TSX / / used to modify the theme state | | └ ─ ─ the state | | | └ ─ ─ index. The TSX / / is used for displaying the theme └─ store ├ ─ theme. TSX // use to store theme stateCopy the code
Create the State component (to display the theme State)
index.tsx
import React from 'react'
const State: React.FC = () => {
return(<div> let me show the global variable </div>)}export default State;
Copy the code
Create the Switch component (to change the theme state)
index.tsx
import React from 'react'
const Switch: React.FC = () => {
return</button> </button> </button>export default Switch;
Copy the code
Now let’s introduce both components into app.tsx
import React from 'react';
import Switch from './pages/switch'
import State from './pages/state'
import './App.css';
const App: React.FC = () => {
return (
<div className="App">
<Switch></Switch>
<State></State>
</div>
);
}
export default App;
Copy the code
Now when we run our project, we can see that the page looks something like this
Now we’re done with the first step
State management
Create a store directory file in the SRC directory and create a new file named theme.tsx
theme.tsx
Initialize the topic value
import React, { createContext, Context } from 'react'ITheme {theme: string} // Initializationexport const initialTheme: ITheme = {
theme: 'Waiting to change subject'} // Create a Context instanceexportconst ThemeContext: Context<any> = createContext(initialTheme); /** * Create a Theme component * All children of the Theme component wrap can be accessed to value */ by calling ThemeContextexport const Theme: React.FC = (props) => {
return (
<ThemeContext.Provider value={{state: initialTheme}}>
{props.children}
</ThemeContext.Provider>
)
}
Copy the code
An important point here is that when the value of themecontext.provider changes, all of its internal child components are rerendered.
So we need to wrap the Theme component around State and Switch
At this point app.tsx becomes
import React from 'react';
import Switch from './pages/switch'
import State from './pages/state'
import { Theme } from './store/theme'
import './App.css';
const App: React.FC = () => {
return (
<div className="App">
<Theme>
<Switch></Switch>
<State></State>
</Theme>
</div>
);
}
export default App;
Copy the code
Now we’re done with step 2
State Read State (useContext)
We can now read the State of the Theme from useContext within the State component
UseContext import React, {useContext} from'react'// Introduce the ThemeContext import {ThemeContext} from'.. /.. /store/theme'Const State: react. FC = () => {// Get the Theme value const {State} = useContext(ThemeContext)return (
<div className="theme light">{state.theme}</div>
)
}
export default State;
Copy the code
Run our project now and see that State has read the value of Theme, indicating that our third step has been successful
Changing state (useReducer)
Next we need to change the Theme value using the two buttons in the Switch to see if the State in the State component has changed
Add reducer in the Theme
Use the useReducer in the Theme component and add the Reducer method to modify the Theme state
import React, { createContext, Context, useReducer } from 'react'ITheme {theme: string} // Initializationexport const initialTheme: ITheme = {
theme: 'Waiting to change subject'} // Create a Context instanceexportconst ThemeContext: Context<any> = createContext(initialTheme); // (Added) Initialize store type, initialize value, reducerexport const CHANGE_THEME: string = 'CHANGE_THEME'; // (added) Compile the reducer functionexport const reducer = (state: ITheme, action: any) => {
switch (action.type) {
case CHANGE_THEME:
return{... state, theme: action.theme } default: throw new Error(); }} /** * Create a Theme component * All children of the Theme component wrap can be accessed to value */ by calling ThemeContextexportConst Theme: react. FC = (props) => {// Update state by using useReducer const [state, dispatch] = useReducer(Reducer, Theme);return (
<ThemeContext.Provider value={{state, dispatch}}>
{props.children}
</ThemeContext.Provider>
)
}
Copy the code
At this point our Theme component is all written.
Switch Add event
The Switch also reads the state of the Theme via useContext and then adds a state-changing Dispatch to the button to change the state of the Theme
The modified Swtich component
import React, { useContext } from 'react'
import { ThemeContext, CHANGE_THEME } from '.. /.. /store/theme'Const Switch: react. FC = () => {// call dispatch to change the state const {dispatch} = useContext(ThemeContext)return (
<section>
<button
onClick={() => {
dispatch({ type: CHANGE_THEME, theme: "Change One"}); </button> <button onClick={() => {dispatch({);type: CHANGE_THEME, theme: "Change Two"}); </button> </section>)}export default Switch;
Copy the code
The effect of running the project is as follows
At this point, all steps are complete.
The demo has been uploaded to GitHub and can be compared with your code 😜
At the end
The original intention of writing this article is to feel that it is too much trouble to use Redux in React. With React Hook, there are fewer repetitive operations. I hope I can share with you. Remember to give me a thumbs-up oh, is a kind of encouragement to me, ha ha!
Other articles
How to change text color dynamically according to background color