React & experience React-dom & React-router & React-redux family bucket with a simple case

1. Preparation

This article is a bit long, so it is recommended to read it patiently. The content of each section is related to the content of the previous section. It is best to go through the case to deepen your memory.

1.1 Create a project

  • In the first step, execute the following command to create a React project.
npx create-react-app react-example
cd react-example
  • The second step is to install dependencies and run the project
yarn install 或 npm install
yarn start 或 npm run start

1.2 Project structure

As shown in the picture:
project structure

1.3 Initialization

src/index.jsDelete the default code of and keep the following part.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
const root = ReactDOM.createRoot(document.getElementById("root"));
const App = () => {
    
    
  return <div>Hello</div>
}
root.render(<App />);

Now the project looks like this, a simple one Hello.
Please add a picture description

2. The basic usage of React

If you are not familiar with the basic syntax of React, you can read the React & daily grammar I wrote earlier .

1.1 output Hello, world

The first step must be to say Hello, world!

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';

const root = ReactDOM.createRoot(document.getElementById("root"));
const App = () => {
    
    
  return <div>Hello, world!</div> // 改动点
}
root.render(<App />);

Please add a picture description

1.2 Use of components

组件It can be created by functions or classes. The above Appfunction is a component, and HTML & JS code can be mixed in it. React will automatically parse these grammars for us. This kind of writing is called just JSX.

Below I will define components as a case in a functional way, and class components will demonstrate when talking about the life cycle.

  • The first step is to define a component Listcalled , and write the content casually, such as Hi List
const List = () => {
    
    
  return <div>Hi List.</div>
}
  • The second step is to introduce List. At present, there is only one entrance App. Obviously, it can only be placed here.
const App = () => {
    
    
  return <div>Hello, world! </List> </div>
}

Effect:
Please add a picture description

1.3 Component nested components

AppComponents like nested Listcomponents, we call this 父子组件, App is the parent component, List is the child component, when the List is placed on the Item component, then the parent component of the Item is List, and the grandparent component is App, and so on.

Now let's Listnest a Itemcomponent for .

const List = () => {
    
    
  // 多行时要用 () 包裹
  return (
    <ul>
      <Item/> // 引入
    </ul>
  )
}
const Item = () => {
    
    
  return <li>item1</li>
}

Effect:
Please add a picture description

Don't forget that you can also write JSX, now try to use Array.map to loop multiple Item components.

const List = () => {
    
    
  return (
    <ul>
      {
    
    [1, 2, 3, 4].map((num) => Item(num) )}
    </ul>
  )
}
const Item = (num) => {
    
    
  return <li key={
    
    num}>item{
    
    num}</li>
}

Before looking at the effect, what changes will happen to the above code?

  1. The Item function component has an extra numparameter , which we use to accept and wrap it {num}in parentheses for access
  2. <Item/>The calling method becomes Item(num), because we want to pass the num value to the Item function, so we found another feature, directly declaring without passing parameters <Item/>will trigger the function.
  3. When looping components, keyattributes must be included and unique.

Effect:
Please add a picture description

1.3 Component binding click event

A dry list, how can it work without interactive behavior,
now let’s define an event, when an item is clicked, the corresponding num value will be prompted, the code is as follows:

const onClickItem = (num) => {
    
    
  alert(num);
}
const Item = (num) => {
    
    
  return <li key={
    
    num} onClick={
    
    () => onClickItem(num)}>item{
    
    num}</li>
}

explain:

  1. Click events are expressed in onClickcamel case, and other events are similar, such as onFocus, onMouse, etc.
  2. onClick={() => 函数} The curly braces return an arrow function, which returns the function we defined, which will be triggered when clicked later.

Don't doubt whether there is a problem with the syntax, even the JSX syntax is there, do you still care about this?

Effect:
Please add a picture description

1.5 Responsive data

The pop-up window is useless, how about directly changing the item data after clicking?
The question is... how to change? Directly set num = xxx? Friends who are familiar with JS should know that when the num parameter is passed [basic type], it is just a copy, and the original num will be invalid after the change.
Even if it works, how do you change the num in the view? It seems that we still have to rely on the syntax provided by React.
Oh no way, let's learn~

  • The first step [1,2,3,4]is useStateto define and export the arroriginal variable , as shown in the figure:
    Please add a picture description
    the effect is still the same as before, and there will be no texture here.

  • The second step is to declare a setArrfunction . The name can be defined freely, but it is generally better to start with set as a specification, indicating that it is used to change the arr data.

const List = () => {
    
    
  const [arr, setArr] = useState([1, 2, 3, 4])
// ...省略
  • The third step is to trigger setArrthe function and change the data in the arr array to achieve the view change effect we want.
    Please add a picture description
    Since setArris defined in the List function component, other functions cannot be accessed directly, so it has to be passed to the past by passing parameters. In onClickItem, it's a bit convoluted, just let it go, I believe you don't mind (/escape).

Here we focus on this piece of code:

setArr(state => {
    
    
  const arr = [...state];
  arr[1] = 1000;
  return arr;
})

After clicking, change arr[1] to 1000, and return the new arr, the effect is as shown in the figure:
Please add a picture description
You may notice that the state is the original arr, and then we copy it to the new arr with the extension symbol , why do you want to do this? Isn't it okay to state[1] = 1000just return and go out? It's unnecessary.

It is possible to do this, the data will change, but the view will not change, because React clearly stipulates: state 是不可变数据,你不能直接改变它,而是要用一份副本去改变.

Why should state adhere to the immutable principle? The official also said that when you want to implement an undo & restore function, there is no way, or is it more complicated to implement? Wouldn’t it be a little unreasonable for React to allow you to go at this time? It’s not the same as eating the last meal and not thinking about the next one.

summary:

  1. useState can declare reactive data.
  2. The state data is immutable and should be replaced by a copy, following the immutable principle.

1.6 What is the hook function Hook Function

In fact, we have already used the hook function. The above useStateis a hook function. React has many built-in hooks, such as useEffect, useRefand so on. I won’t introduce them one by one here, just understand that all the hook functions that start usewith are hook functions.

We can also customize hooks. The question is, what kind of scenarios do we need? What is written in it?
In fact, there is no single answer to this. Everyone has a different understanding of hooks, resulting in thousands of types of hooks .

Personally, I prefer to classify it as 处理脏活a type of function. More generally, it is used for processing 响应式数据. For example, there is a functional module for the prize business. For this module, there may be logic for verifying the configuration of prizes. Then I will Several hook functions will be added to this prize for easy subsequent calls.

const usePrize = () => {
    
    
	const verifyPrizeConfig = (state) => {
    
    
		// Do something ...
	}
	const resetPrizeConfig = (state) => {
    
    
		// Do something ...
	}
	return [
		verifyPrizeConfig,
		resetPrizeConfig,
	]
}
const [ verifyPrizeConfig ] = usePrize();

1.7 Component life cycle

When each component is rendered, React will trigger some built-in functions step by step. These are called "lifecycle functions". We can do some business processing according to different cycle functions. For example, I want to request the interface to get data before the component is rendered. .

It should be noted here that 函数组件there is no lifecycle function, only 类组件one. In this case, we can turn Appthis component into a class component, and keep the other things unchanged. Who stipulates 类组件that it cannot be nested 函数组件?

  • The first step is to change the App function component to a class component, as follows:
// 源 App 函数组件
// const App = () => {
    
    
//   return <div>Hello, world! <List/> </div>
// }
// 新 APP 类组件
class App extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
  }
  render() {
    
    
    return <div>Hello, world! <List /> </div>
  }
}
  • The second step is to add a lifecycle function. Here, the most common componentDidMountfunction to indicate that the component is triggered in advance when it is rendered for the first time.
class App extends React.Component {
    
    
  // 省略
  componentDidMount() {
    
    
    // Do something...
    alert('Init')
  }
}

Please add a picture description

1.8 Function component simulation life cycle

You may think, this is not fair, why does the function component not have a periodic function? Don't worry, the hook function provided by React useEffectwill come in handy. This hook can completely simulate the three core functions of the life cycle:

componentDidMount() {
    
    } 组件第一次渲染时,就刚刚用到的
componentDidUpdate() {
    
    } 组件数据更新时(state 更新)
componentWillUnMount() {
    
    } 组件销毁时

The way to use it is also very simple. Here we take the List component as an example, and we must not forget our old partner~

  • The first step, simulation componentDidMount, is as follows:
import {
    
     useState, useEffect } from 'react';
const List = () => {
    
    
  const [arr, setArr] = useState([1, 2, 3, 4]);
  // 模拟 componentDidMount
  useEffect(() => {
    
    
    alert('List init') 
  });
  return (
    <ul>
      {
    
    arr.map((num) => Item(num, setArr) )}
    </ul>
  )
}

Please add a picture description

  • The second step, simulation componentDidUpdate, listens to the state in the second parameter of useEffect:
// ... 省略
const [arr, setArr] = useState([1, 2, 3, 4])
 useEffect(() => {
    
    
    alert('List init')
  }, [arr]) // componentDidUpdate

When clicking to update data, this function will be triggered again, as shown in the figure:
Please add a picture description
Please add a picture description

  • The third step is to simulate componentWillUnMount, just return a function in useEffect.
const [arr, setArr] = useState([1, 2, 3, 4])
 useEffect(() => {
    
    
    alert('List init')
    return () => {
    
     // componentWillUnMount
      alert('List destroyed!');
    };
  }, [arr])

When does componentWillUnMount trigger? In fact, whenever the state is updated, the component will be re-rendered, which is a destruction behavior, so when you click to update the data, componentWillUnMount will be triggered first, and then componentDidUpdate will be triggered.
Effect:

Please add a picture description
Please add a picture description
Please add a picture description

Three, React-router-dom

1.1 What is React-router-dom

How can one page be enough? Now we want to click on the item to enter another page without refreshing the page. Here we can use the plug-in React-router-dom provided by React, commonly known as it 路由.

1.2 Differences between React-router-dom and React-router versions

React-router-dom is a new version based on the transformation of React-router, which is the most commonly used version now React-router-dom.
In this case, React-router-dom will be used as a demonstration.

1.3 Use of React-router-dom

  • The first step is to download react-router-dom.
yarn add react-router-dom
  • The second step is to introduce src/index.jsin .
import {
    
    
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";
  • The third step is to remodel our previous App component introduction method
// 旧代码
// root.render(<App />);
// 新代码
const router = createBrowserRouter([
  {
    
    
    path: "/",
    element: <App/>,
  },
]);

root.render(<RouterProvider router={
    
    router} />);

Now the effect is the same as before, here are the steps to explain:

  1. Replace the App in the original root.render with RouterProviderthe component
  2. createBrowserRouteIntroduce App inside element.
  3. path ( 路由), the App component will only be rendered when /the root .
  • The fourth step is to create a new AppDetailcomponent and mount it /detailon the route.
const AppDetail = () => {
    
    
	return <h1>Detail data</h1>
}
const router = createBrowserRouter([
  {
    
    
    path: "/",
    element: <App/>,
  },
  // 挂载到 /detail 路由
  {
    
    
    path: "/detail",
    element: <AppDetail/>,
  },
]);
  • The fifth step, visit /detailto see the effect
    Please add a picture description
  • The sixth step is to access by clicking and jumping /detail, and <Link>the label .
import {
    
    
  createBrowserRouter,
  RouterProvider,
  Link,
} from "react-router-dom";
const Item = (num, setArr) => {
    
    
  return (
    <li key={
    
    num} onClick={
    
    () => onClickItem(num, setArr)}>
      <Link to='/detail'>item{
    
    num}</Link>
    </li>
  )
}

Effect:
Please add a picture description

react-router-dom is as simple as that. As for the use of other APIs, you can refer to the documentation, and I won’t explain too much here.

4. React-redux

1.1 What is React-redux

React-redux is a tool that can be used to manage the global state state, so that components can access the same state.

1.2 When to use React-redux

When multiple components reuse the same state, you can consider using redux to promote it to the global for easy maintenance.

1.3 React-redux download & configuration

  • The first step is to download react-redux. The official here also provides a toolkit @reduxjs/toolkit, which contains all the functions of react-redux and some other built-in functions. It is highly recommended by the official. Download these two together.
yarn add react-redux @reduxjs/toolkit
  • The second step is to create a new store/index.jsfile , which is responsible for managing the global state. The initialization content is as follows:
// ./src/store/index.js
import {
    
     configureStore, createSlice } from '@reduxjs/toolkit'
const userSlice = createSlice({
    
    
  name: 'User', // name 必填的,当前作用域的标识符,可以理解为 nameSpace 命名空间,否则页面上无法正常展示。
  initialState: {
    
     // 声明 state 的地方
  },
  reducers: {
    
     // 声明 reducer 函数的地方
  }
});
// 将 store 导出去。
const store = configureStore({
    
    
  reducer: userSlice.reducer
})

export default store;

  • The third step is src/index.jsto introducestore
import store from './store/index';
import {
    
     Provider } from 'react-redux'
root.render(
  <Provider store={
    
    store}>
    <RouterProvider router={
    
    router} />
  </Provider>
);

explain:

  1. Import storethe object .
  2. Import Providerthe component and RouterProvider wrap the original component.
  3. will be passed storeas a parameter to Providerthe component.

At present, the page is no different from the original one, but now we have more functions of redux, why not do it.

1.4 What is Reducer

ReducerIt has almost the same meaning as mutations in Vuex, which specifically defines some functions for processing state. The reducer mainly accepts a state and an action, processes related logic according to these two parameters, and then returns a new state ( ) 遵循前面所说的“不可变原则”.

1.5 What is dispatch(action)

  • dispatchis used to call the reducer function.
  • actionIt is a description object to be passed when dispatch calls the reducer function, so that the reducer knows what to do. The description object has two parameters in total: type/ payload, type is the name of the function that calls the reducer, and payload is the data we want to pass as a parameter for the reducer to accept.

1.6 use

After understanding reducer/dispatch/actionthe three core concepts, let's start using:

  • The first step is to define global responsive data in initialStatethe object .
// 省略...
initialState: {
    
    
	// 新增
    user: {
    
    
      name: 'Jack',
      desc: 'Hello,world!'
    }
},
  • The second step is to create a new Usercomponent , which is used to access the responsive data declared above, and mount it to App and AppDetail for rendering. The code is as follows:
// ./src/index.js
// ...省略
import {
    
     Provider, useSelector } from 'react-redux'
// 新增
const User = () => {
    
    
  // 用 redux 提供的钩子来获取 state
  const user = useSelector(state => state.user); 
  return (
    <div>
      <span>{
    
    user.name}</span>
      <span> says: {
    
    user.desc}</span>
    </div>
  )
}
// ./src/index.js
// ...省略
class App extends React.Component {
    
    
  // ...省略
  render() {
    
    
    return (
      <div>
        <User /> // 新增:挂载 User
        <List /> 
      </div>
    )
  }
}
const AppDetail = () => {
    
    
  return (
    <h1>
      Detail data
      <User /> // 新增:挂载 User
    </h1>
  )
}

Current effect: Jack says: Hello, world!
Please add a picture description

  • The third step is to declare reducerthe function to change the state data.
// .src/store/index.js
// ...省略
reducers: {
    
     // 声明 reducer 函数的地方
	// 新增
    changeUserInfo(state, action) {
    
    
      const {
    
     payload } = action;
      switch(payload.state) {
    
    
        case 'name':
          return {
    
    
            ...state,
            user: {
    
    
              ...state.user,
              name: '杰克',
            }
          }
        case 'desc':
          return {
    
    
            ...state,
            user: {
    
    
              ...state.user,
              desc: '你好,世界!',
            }
          }
        default:
          return state;
      }
    }
  }

changeUserInfo function explanation:

  1. According to payload.state, that is, the data we are going to pass parameters to change the username name or describe
    desc
  2. Following the principle of not destroying the state, here we use extensions to merge.
  • The fourth step is to use dispatch(action)to trigger the reducer to complete the change effect.
// ./src/index.js
import {
    
     Provider, useSelector, useDispatch } from 'react-redux'
const User = () => {
    
    
  const user = useSelector(state => state.user);
  const dispatch = useDispatch(); // 引入触发 reducer 的钩子
  return (
    <div>
      <span>{
    
    user.name}</span>
      <span> says: {
    
    user.desc}</span>
      // 以下是新增的
      <button onClick={
    
    () => dispatch({
    
    
        type: 'User/changeUserInfo',
        payload: {
    
    
          state: 'name'
        }
      })}>
        更换名字
      </button>
      <button onClick={
    
    () => dispatch({
    
    
        type: 'User/changeUserInfo',
        payload: {
    
    
          state: 'desc'
        }
      })}>
        更换描述
      </button>
    </div>
  )
}

Now look at the overall effect:
Please add a picture description

V. Summary

Unknowingly, we have used React-dom & React-router& React-redux:

root.render( // react-dom
  <Provider store={
    
    store}> // react-redux
    <RouterProvider router={
    
    router} /> // react-router-dom
  </Provider>
);

Congratulations, you have successfully started the React family bucket, and the rest is left to the practice time to help us practice makes perfect.

If you have any questions, please point them out!

over!


The case has been put on github

Guess you like

Origin blog.csdn.net/cookcyq__/article/details/129331505
Recommended