React + 项目(从基础到实战) -- 第十期

目标

学会react 状态管理工具

使用redux管理用户状态

Context

  1. 跨层级传递,不像props层层传递
  2. 类似于Vue的provide/inject
  3. 用于:切换主题颜色,切换语言

useReducer

useState 的替代方案

简化版的redux

MobX

1. MobX 介绍 · MobX 中文文档

声明式的修改数据 , 像vue

state

action

derivation 派生: computed observer

Redux

  • state/store (存储的数据)
  • action(发布的命令 类似导航让我们知道发生了什么)
  • reducer(生成新的state 联系起state与action)
  • dispatch(派发的action,产生数据)

默认支持跨组件通讯

项目实战--redux

快速开始 | Redux 中文官网

Redux 要求我们通过创建数据副本和更新数据副本,来实现不可变地写入所有状态更新。不过 Redux Toolkit createSlicecreateReducer 在内部使用 Immer 允许我们编写"可变"的更新逻辑,变成正确的不可变更新

引入redux

安装

npm install @reduxjs/toolkit react-redux

为 React 提供 Redux Store

js 复制代码
import React from 'react'

import ReactDOM from 'react-dom/client'

import App from './App.tsx'

import { Provider } from 'react-redux'

import store from './store/index.ts'

ReactDOM.createRoot(document.getElementById('root')!).render(

  <React.StrictMode>

    <Provider store={store}>

      <App />

    </Provider>

  </React.StrictMode>,

)

创建Redux Store

js 复制代码
import { configureStore } from '@reduxjs/toolkit'

import userReducer from './userReducer'

export default configureStore({

  reducer: {

    //分模块注册

    user: userReducer, // 注册userReducer

  

    // 你可以在这里注册更多的reducer

  }

})

创建 Redux State Slice

js 复制代码
import { createSlice , PayloadAction } from "@reduxjs/toolkit";

  

export type UserStateType={

    username:string,

    nickname:string

}

  
  

const INIT_STATE:UserStateType={

    username:"",

    nickname:""

}

  
  

export const userSlice=createSlice({

    name:"user",

    initialState:INIT_STATE,

    reducers:{

        //登录保存用户信息

        loginReducer:(state,action:PayloadAction<UserStateType>)=>{

            return action.payload // 设置username nickname 到 redux store

            //用不到immer

  

        },

        //退出删除用户信息

        logoutReducer:()=>{

            return INIT_STATE // 设置username nickname 到 redux store

            //用不到immer

        }

    }

})

  
  

export const {loginReducer,logoutReducer}=userSlice.actions

export default userSlice.reducer

使用

用户信息存储

自定义hook

js 复制代码
import { useEffect , useState } from "react";

  

import { useRequest } from "ahooks";

//导入发起请求的函数

  

import { useDispatch } from "react-redux";

import { getUserInfoService } from "../services/user";

import { loginReducer } from "../store/userReducer";

import useGetUserInfo from "./useGetUserInfo";

  

function useLoadUserData() {

    const dispatch = useDispatch();

    const [waitingUserData , setWaitingUserData] = useState(true);

  

   //ajax 加载用户信息

   const {run } = useRequest(getUserInfoService , {

       manual:true,

       onSuccess: (data) => {

         const {username , nickname} = data;

         dispatch(loginReducer({

            username,

            nickname

         })) // 存储到redux store

       },

       onFinally(){

        setWaitingUserData(false);

       }

   })

  
  
  

   //判断当前的redux  store 是否存在用户信息

   const {username} = useGetUserInfo()

   useEffect(() => {

       if(username){

           setWaitingUserData(false); // redux中存在信息,则不用重新加载

           return ;

       }

       run();// 如果不存在,则进行加载

   },[username])

  
  

   return {waitingUserData};

  

}

  
  

export default useLoadUserData;

由于后端有延迟,首页闪了一下,前端使用spin组件(显示加载效果)

bug :用户登录成功后.还能访问登录注册页

预期效果:

已经登录

  1. 跳转页面是登录注册页 , 重定向到我的问卷

  2. 跳转页面不是登录注册页,放行

未登录

  1. 跳转页面需要用户信息,重定向到登录页

  2. 跳转页面不需要用户信息,放行

自定义hook

js 复制代码
import React , {FC, useEffect} from "react";

import useGetUserInfo from "./useGetUserInfo";

import { useNavigate ,useLocation } from "react-router-dom";

import useLoadUserData from "./useLoadUserData";

import { isLoginOrRegiter, isNeedUserInfo, LOGIN_PATH, MANAGE_PATH } from "../router";

  

function useNavPage() {

    const {waitingUserData} = useLoadUserData();

    const {username} = useGetUserInfo();

    const {pathname} = useLocation();

  

    const nav = useNavigate();

    useEffect(()=>{

        if(waitingUserData) return ;

  

        //已经登录了

        if(username){

            //跳转的页面是login/register

            if(isLoginOrRegiter(pathname))

             {

                nav(MANAGE_PATH)

             }

            return

        }

  

        //没有登录

        if(isNeedUserInfo(pathname))

        {

            nav(LOGIN_PATH);

        }

  
  
  

    },[username,pathname])

  

}

  
  
  

export default useNavPage;

总结

自定义hook使用

useGetUserInfo

useLoadUserData

useNavPage

相关推荐
shenweihong5 分钟前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
齐 飞7 分钟前
MongoDB笔记02-MongoDB基本常用命令
前端·数据库·笔记·后端·mongodb
巧克力小猫猿23 分钟前
基于ant组件库挑选框组件-封装滚动刷新的分页挑选框
前端·javascript·vue.js
FinGet32 分钟前
那总结下来,react就是落后了
前端·react.js
前端李易安33 分钟前
手写一个axios方法
前端·vue.js·axios
XinZong1 小时前
【VSCode插件推荐】想准时下班,你需要codemoss的帮助,分享AI写代码的愉快体验,附详细安装教程
前端·程序员
trim1 小时前
写了个可以在工作中快速摄取知识的神器,都来体验体验
前端·产品
ErvinHowell1 小时前
文件MD5生成性能大提升!如何实现分片与Worker优化
前端·vue.js·算法
想做白天梦1 小时前
LeetCode :150. 逆波兰表达式求值(含求后缀表达式和中缀转后缀表达式)
java·前端·算法
迃-幵1 小时前
力扣:225 用队列实现栈
android·javascript·leetcode