【从零开始学 React | 第九章】Class类组件zustand
前言:本章主要讲解了React Class 类组件的基础写法、生命周期、组件通信,以及Zustand 状态管理库的基础使用、异步操作和模块化切片模式。
【从零开始学 React | 第九章】Class类组件&zustand
- 一:Class类组件
- 1.基础结构:
- 2.生命周期函数:
- 3.组件通信:
- 二:zustand
- 1.基础结构
- 2.异步支持
- 3.切片模式
一:Class类组件
概念:
Class 类组件是使用 ES6 类(class)语法定义的、有自己独立状态(state)和生命周期的 React 组件。
1.基础结构:
类组件就是通过 JS 中的类来组织组件的代码:
classCounterextendsComponent{// 定义状态变量state={count:0}// 事件回调clickHandler=()=>{this.setState({count:this.state.count+1})}// UI模板(JSX)render(){return<button onClick={this.clickHandler}>{this.state.count}</button>}}1.通过类属性state定义状态数据
2.通过setState方法来修改状态数据
3.通过render来写 UI 模版(JSX 语法一致)
hook和它的区别:
1.写法更简单
类组件:class + render () + this
Hook 组件:普通函数 + return,不用写 this
2.状态管理不同
类组件:this.state + this.setState()
Hook 组件:useState() 直接定义、修改
3.代码量更少
同样功能,Hook 代码少 30%~50%
4.使用场景
类组件:老项目、旧代码
Hook 组件:现在官方推荐、新项目全用这个
2.生命周期函数:
概念:组件从创建到销毁的各个阶段自动执行的函数就是生命周期函数
案例:
// Class API 生命周期import{Component,useState}from"react"classSonextendsComponent{// 声明周期函数// 组件渲染完毕执行一次 发送网络请求componentDidMount(){console.log('组件渲染完毕了,请求发送起来')// 开启定时器this.timer=setInterval(()=>{console.log('定时器运行中')},1000)}// 组件卸载的时候自动执行 副作用清理的工作 清除定时器 清除事件绑定componentWillUnmount(){console.log('组件son被卸载了')// 清除定时器clearInterval(this.timer)}render(){return<div>i am Son</div>}}functionApp(){const[show,setShow]=useState(true)return(<>{show&&<Son/>}<button onClick={()=>setShow(false)}>unmount</button></>)}exportdefaultApp3.组件通信:
概念:类组件和 Hooks 编写的组件在组件通信的思想上完全一致
三种通信方式
父传子:通过 prop 绑定数据
子传父:通过 prop 绑定父组件中的函数,子组件调用
兄弟通信:状态提升,通过父组件做桥接
案例:
// Class APIimport{Component}from"react"classCounterextendsComponent{// 编写组件的逻辑代码// 1. 状态变量 2. 事件回调 3.UI(JSX)// 1. 定义状态变量state={count:0}// 2. 定义事件回调修改状态数据setCount=()=>{// 修改状态数据this.setState({count:this.state.count+1})}render(){return<button onClick={this.setCount}>{this.state.count}</button>}}functionApp(){return(<><Counter/></>)}exportdefaultApp1.父传子 直接通过prop子组件标签身上绑定父组件中的数据即可
2.子传父 在子组件标签身上绑定父组件中的函数,子组件中调用这个函数传递参数
总结
1.思想保持一致
2.类组件依赖于this
二:zustand
概念:
Zustand 是一个轻量、简单、无 Provider 的 React 状态管理库,用于跨组件共享数据,比 Redux 更简洁易用。
官网:zustand
1.基础结构
语法:
import{create}from'zustand'constuseStore=create((set)=>({// 同步数据count:0,// 同步方法:直接 set 修改状态addCount:()=>{set({count:10})},// 基于旧值修改increment:()=>{set((state)=>({count:state.count+1}))}}))1.函数参数必须返回一个对象 对象内部编写状态数据和方法
2.set是用来修改数据的专门方法必须调用它来修改数据
语法1:参数是函数 需要用到老数据的场景
语法2:参数直接是一个对象 set({ count: 100 })
案例:
// zustandimport{create}from'zustand'//1. 创建storeconstuseStore=create((set)=>{return{// 状态数据count:0,// 修改状态数据的方法inc:()=>{set((state)=>({count:state.count+1}))}}})// 2. 绑定store到组件// useStore => { count, inc }functionApp(){const{count,inc}=useStore()return(<><button onClick={inc}>{count}</button></>)}exportdefaultApp2.异步支持
对于异步的支持不需要特殊的操作,直接在函数中编写异步逻辑,最后只需要调用 set 方法传入新状态即可
语法:
constuseStore=create((set)=>({list:[],getList:async()=>{const{data}=awaitaxios.get('/api/xxx')set({list:data})}}))案例:
// zustandimport{useEffect}from'react'import{create}from'zustand'constURL='...'// 1. 创建storeconstuseStore=create((set)=>{return{// 状态数据count:0,// 修改状态数据的方法inc:()=>{set((state)=>({count:state.count+1}))},channelList:[],fetchGetList:async()=>{constres=awaitfetch(URL)constjsonRes=awaitres.json()set({channelList:jsonRes.data.channels})}}})// 2. 绑定store到组件// useStore => { count, inc }functionApp(){const{count,inc,fetchGetList,channelList}=useStore()useEffect(()=>{fetchGetList()},[fetchGetList])return(<><button onClick={inc}>{count}</button><ul>{channelList.map(item=><li key={item.id}>{item.name}</li>)}</ul></>)}exportdefaultApp3.切片模式
场景:当单个 store 比较大的时候,可以采用 切片模式 进行模块拆分组合,类似于模块化
语法:
1.步骤 1:定义独立切片(countStore /channelStore)
// 切片1:countStore(计数器相关状态与方法)constcountSlice=(set)=>({count:0,increment:()=>set((state)=>({count:state.count+1})),reset:()=>set({count:0})})// 切片2:channelStore(频道列表相关状态与异步方法)constchannelSlice=(set)=>({channelList:[],loading:false,fetchChannels:async()=>{set({loading:true})const{data}=awaitaxios.get('/api/channels')set({channelList:data.channels,loading:false})}})2.步骤 2:合并切片,创建根 store(rootStore)
import{create}from'zustand'// 合并所有切片,生成根storeconstuseRootStore=create((...a)=>({...countSlice(...a),...channelSlice(...a)}))exportdefaultuseRootStore步骤 3:组件中使用根 store
functionComponent(){// 从根store中按需取状态和方法const{count,increment,channelList,fetchChannels}=useRootStore()return(<div><p>计数:{count}</p><button onClick={increment}>+1</button><button onClick={fetchChannels}>加载频道</button><ul>{channelList.map(c=><li key={c.id}>{c.name}</li>)}</ul></div>)}最后:
如果我的内容对你有帮助,请点赞,评论,收藏,创作不易。大家的支持就是我坚持下去的动力!
