书籍管理网站建设需求文档,深圳景观设计公司10强,wordpress右侧固定,商城网站后续费用注#xff1a;Redux最新用法参考 个人React专栏 react 初级学习
Hooks基本介绍------------------------- Hooks#xff1a;钩子、钓钩、钩住#xff0c; Hook 就是一个特殊的函数#xff0c;让你在函数组件中获取状态等 React 特性 #xff0c;是 React v16.8 中的新增功…注Redux最新用法参考 个人React专栏 react 初级学习
Hooks基本介绍------------------------- Hooks钩子、钓钩、钩住 Hook 就是一个特殊的函数让你在函数组件中获取状态等 React 特性 是 React v16.8 中的新增功能 作用为函数组件提供状态、生命周期等原本 class 组件中提供的 React 功能 可以理解为通过 Hooks 为函数组件钩入 class 组件的特性 注意Hooks 只能在函数组件中使用自此函数组件成为 React 的新宠儿
React v16.8 版本前后组件开发模式的对比 React v16.8 以前 class 组件(提供状态) 函数组件(展示内容) React v16.8 及其以后 class 组件(提供状态) 函数组件(展示内容) Hooks(提供状态) 函数组件(展示内容) 混用以上两种方式部分功能用 class 组件部分功能用 Hooks函数组件
总结
注意1虽然有了 Hooks但 React 官方并没有计划从 React 库中移除 class
注意2有了 Hooks 以后不能再把函数组件称为无状态组件了因为 Hooks 为函数组件提供了状态
为什么要有 Hooks
组件的状态逻辑复用 在 Hooks 之前组件的状态逻辑复用经历了mixins混入、HOCs高阶组件、render-props 等模式 早已废弃mixins 的问题1 数据来源不清晰 2 命名冲突 HOCs、render-props 的问题重构组件结构导致组件形成 JSX 嵌套地狱问题 class 组件自身的问题 选择函数组件和 class 组件之间的区别以及使用哪种组件更合适 需要理解 class 中的 this 是如何工作的 相互关联且需要对照修改的代码被拆分到不同生命周期函数中 相比于函数组件来说不利于代码压缩和优化也不利于 TS 的类型推导
注意
之前的react语法并不是以后就不用了class 组件相关的 API 在hooks中可以不用
class 自身语法比如constructor、static 等钩子函数componentDidMount、componentDidUpdate、componentWillUnmountthis 相关的用法
useState-Hooks
useState-基本使用 useState作用为函数组件提供状态state,不能在类组件中调用 useState使用场景当你想要在函数组件中使用组件状态时就要使用 useState Hook 了 约定修改状态的函数名称以 set 开头后面跟上状态的名称 多次调用 useState 多个状态和修改状态的函数之间不会相互影响 useState 提供的状态是函数内部的局部变量可以在函数内的任意位置使用 每次渲染useState 获取到的都是最新的状态值(react会记住最新的状态值),useState 的初始值(参数)只会在组件第一次渲染时生效。
语法
import { useState } from react// 参数状态初始值可以是任意值
// 返回值stateArray 是一个数组
const stateArray useState(0)// 索引 0 表示状态值state
const state stateArray[0]
// 索引 1 表示修改状态的函数setState(newValue) 是一个函数参数表示*新的状态值*
const setState stateArray[1]状态的读取和修改
读取状态 const Counter () { const [user, setUser] useState({ name: jack, age: 18 }) return ( div p姓名{user.name}/p p年龄{user.age}/p /div ) } 修改状态 调用该函数后将使用新的状态值替换旧值修改状态后因为状态发生了改变所以该组件会重新渲染setUser(newValue) 是一个函数参数表示新的状态值 。调用这个函数新的状态值会覆盖原来的状态值所以这里和class的setState不一样区分一下class的setState需要修改哪个值就传哪个值内部会做状态的合并hooks呢修改状态值会直接覆盖不会合并所以hooks修改状态值需要先对原来的值进行取值解构再修改。
const Counter () {// 利用数组解构提取状态和修改状态const [user, setUser] useState({ name: jack, age: 18 })const onAgeAdd () {setUser({...user,age: user.age 1})}return (divp姓名{user.name}/pp年龄{user.age}/pbutton onClick{onAgeAdd}年龄1/button/div)
}
useState-使用规则 如何为函数组件提供多个状态 调用 useState Hook 多次即可每调用一次 useState Hook 可以提供一个状态 useState Hook 多次调用返回的 [state, setState]相互之间互不影响 useState 等 Hook 的使用规则 React Hooks 只能直接出现在 函数组件 中 React Hooks不能嵌套在 if/for/其他函数 中 原理React 是按照 Hooks 的调用顺序来识别每一个 Hook如果每次调用的顺序不同导致 React 无法知道是哪一个 Hook
useEffect-Hooks
useEffect-基本含义
作用处理函数组件中的副作用side effect副作用是相对于主作用来说的一个功能比如函数除了主作用其他的作用就是副作用 对于 React 组件来说主作用就是根据数据state/props渲染 UI除此之外都是副作用比如手动修改 DOM常见的副作用side effect数据Ajax请求、手动修改 DOM、localStorage、console.log 操作等useEffect完全指南useEffect 完整指南 — Overreacted
useEffect-基本使用 使用时机
import { useEffect } from react// 1
// 触发时机 第一次渲染会执行 、 每次组件重新渲染都会再次执行
// componentDidMount ComponentDidUpdate
useEffect(() {})// 2使用频率最高
// 触发时机只在组件第一次渲染时执行
// componentDidMount
useEffect(() {}, [])// 3使用频率最高
// 触发时机1 第一次渲染会执行 2 当 count(某个状态) 变化时才会次执行
// componentDidMount componentDidUpdate判断 count 有没有改变
useEffect(() {}, [count])// 4
useEffect(() {// 返回值函数的执行时机组件卸载时// 在返回的函数中清理工作return () {// 相当于 componentWillUnmount}
}, [])//5
useEffect(() {// 返回值函数的执行时机1 组件卸载时 2 count 变化时// 在返回的函数中清理工作return () {}
}, [count]) 发送请求 在组件中可以使用 useEffect Hook 来发送请求side effect获取数据 注意effect 只能是一个同步函数不能使用 async 因为如果 effect 是 async 的此时返回值是 Promise 对象。这样的话就无法保证清理函数被立即调用 为了使用 async/await 语法可以在 effect 内部创建 async 函数并调用
// 错误演示不要给 effect 添加 async
useEffect(async () {const res await axios.get(http://xxx)return () {}
}, [])// 正确使用
useEffect(() {const loadData async () {const res await axios.get(http://xxx)}loadData()return () {}
}, [])
useContext-Hooks
作用
在函数组件中获取 Context 中的值。要配合 Context 一起使用。
语法 useContext 的参数Context 对象即通过 createContext 函数创建的对象 useContext 的返回值Context.Provider 中提供的 value 数据
import { useContext } from reactconst { color } useContext(ColorContext)
useContext Hook 与Context.Consumer 的区别获取数据的位置不同 Context.Consumer在 JSX 中获取 Context 共享的数据 useContext在 JS 代码 或者 JSX 中获取 Context 的数据
const ColorContext createContext()const Child () {// 在普通的 JS 代码中const { color } useContext(ColorContext)return (divuseContext 获取到的 color 值{ color }{/* 在 JSX 中 */}ColorContext.Consumer{color span共享的数据为{color}/span}/ColorContext.Consumer/div)
}
useState-useRef
useRef-用法 参数在获取 DOM 时一般都设置为 null获取 DOM 对象时如果拿不到 DOM 对象此时获取到的值就是 null 返回值包含 current 属性的对象。 注意只要在 React 中进行 DOM 操作都可以通过 useRef Hook 来获取 DOM比如获取 DOM 的宽高等 注意useRef不仅仅可以用于操作DOM还可以操作组件
import { useRef } from reactconst App () {// 1 使用useRef能够创建一个ref对象const inputRef useRef(null)const add () {// 3 通过 inputRef.current 来访问对应的 DOMconsole.log(inputRef.current.value)inputRef.current.focus()}return (section classNametodoapp{/* 2 将 ref 对象设置为 input 的 ref 属性值。目的将 ref 对象关联到 input 对应的 DOM 对象上 */}input typetext placeholder请输入内容 ref{inputRef} /button onClick{add}添加/button/section)
}export default App Redux基本介绍------------------------
作用集中式存储和管理应用的状态、处理组件通讯问题时无视组件之间的层级关系、简化大型复杂应用中组件之间的通讯问题、数据流清晰易于定位 Bug
Redux核心概念
为了让代码各部分职责清晰、明确Redux 代码被分为三个核心概念action/reducer/store
action动作 描述要做的事情特点只描述做什么 是一个js对象必须带有type属性用于区分动作的类型 根据功能的不同可以携带额外的payload有效的载荷参数数据来完成相应功能 例如 计数器功能描述
{ type increment, payload: 10 } // 10
{ type decrement, payload: 10 } // -10 为了使action功能 多元并且灵活化需要使用 action creator 函数去创建action目的简化多次使用 action 时重复创建 action 对象函数返回值依然是个action对象。 const decrement payload ({ type: decrement, payload })
reducer函数
用来处理 action 并更新状态是 Redux 状态更新的地方 函数签名为(prevState, action) newState 接收上一次的状态和 action 作为参数根据 action 的类型执行不同操作最终返回新的状态注意该函数一定要有返回值即使状态没有改变也要返回上一次的状态 约定reducer 是一个纯函数相同的输入总是得到相同的输出并且不能包含 side effect 副作用(比如不能修改函数参数、不能修改函数外部数据、不能进行异步操作等) 对于 reducer 来说为了保证 reducer 是一个纯函数不要 不要直接修改参数 state 的值也就是不要直接修改当前状态而是根据当前状态值创建新的状态值 不要使用 Math.random() / new Date() / Date.now() / ajax 请求等不纯的操作 不要让 reducer 执行副作用side effect // 示例
// state 上一次的状态
// action 当前要执行的动作
const reducer (state10, action) {switch (action.type) {// 计数器增加case increment:// 返回新状态// return state 1// 根据 action 中提供的 payload 来决定到底增加多少return state action.payload// 注意一定要有 default如果将来 reducer 无法处理某个 action就直接将上一次的状态返回即可default:return state}
}
store仓库 整合 action 和 reducer一个应用只有一个 store 维护应用的状态获取状态store.getState() 发起状态更新时需要分发 actionstore.dispatch(action) 创建 store 时接收 reducer 作为参数const store createStore(reducer) 订阅(监听)状态变化const unSubscribe store.subscribe(() {}) 取消订阅状态变化 unSubscribe()
核心代码
import {createStore} from redux// 创建 store
// 参数为reducer 函数
const store createStore(reducer)// 更新状态
// dispatch 派遣派出。表示分发一个 action也就是发起状态更新
store.dispatch(action)
store.dispatch( increment(2) )// 获取状态
const state store.getState()// 其他 API------
// 监听状态变化
const unSubscribe store.subscribe(() {// 状态改变时执行相应操作// 比如记录 redux 状态console.log(store.getState())
})// 取消监听状态变化
unSubscribe()
Redux获取状态默认值执行过程
只要创建 store给createStore(传递了 reducer)那么Redux 就会调用一次 reducerRedux 内部第一次调用 reducer reducer的默认传值的type和payload为 (undefined, {type: redux/INITv.a.4.t.t.p})因为传入的状态值是 undefined 并且是一个随机的 action type因为是一个随机的 action type所以reducer 中 switch 一定无法处理该 action那就一定会走 default。也就是直接返回了状态的默认值10Redux 内部拿到状态值store.getState()比如此处的 10以后就用这个状态值来作为了 store 中状态的默认值
Redux代码执行流程 创建 store 时Redux 就会先调用一次 reducer来获取到默认状态10 然后分发动作 store.dispatch(action)更新状态 只要调用了dispatch操作Redux store 内部就会调用 reducer 传入上一次的状态当前示例中就是10和当前传入的 action{ type: increment }计算出新的状态并返回 reducer 执行完毕后将最新的状态交给 storestore 用最新的状态替换旧状态状态更新完毕
import { createStore } from redux
const store createStore(reducer)// reducer(10, { type: increment })
function reducer(state 10, action) {console.log(reducer:, state, action)switch (action.type) {case increment:return state 1default:return state}
}console.log(状态值为, store.getState()) // 10// 发起更新状态
// 参数 action 对象
store.dispatch({ type: increment })
// 相当于 reducer(10, { type: increment })console.log(更新后, store.getState()) // 11
React-Redux介绍
react-redux 库是 Redux 官方提供的 React 绑定库为 React 接入 Redux实现在 React 中使用 Redux 进行状态管理。 React 和 Redux 是两个独立的库两者之间职责独立。因此为了实现在 React 中使用 Redux 进行状态管理 就需要一种机制将这两个独立的库关联在一起。这时候就用到 React-Redux 这个绑定库了。
react-redux 文档
react-redux 的使用分为两大步
1 全局配置只需要配置一次 安装 react-redux yarn add react-redux 从 react-redux 中导入 Provider 组件 导入创建好的 redux 仓库 使用 Provider 包裹整个应用 将导入的 store 设置为 Provider 的 store 属性值
index.js// 导入 Provider 组件
import { Provider } from react-redux
// 导入创建好的 store
import store from ./storeReactDOM.render(Provider store{store}App //Provider,document.querySelector(#root)
)
2 组件接入获取状态或修改状态
获取状态useSelector hook useSelector获取 Redux 提供的状态数据 参数selector 函数用于从 Redux 状态中筛选出需要的状态数据并返回 返回值筛选出的状态
import { useSelector } from react-reduxconst App () {const count useSelector(state state)return (divh1计数器{count}/h1button数值增加/buttonbutton数值减少/button/div)
}
修改状态useDispatch hook useDispatch拿到 dispatch 函数分发 action修改 redux 中的状态数据
import { useDispatch } from react-reduxconst App () {const dispatch useDispatch()return (divh1计数器{count}/h1{/* 调用 dispatch 分发 action */}button onClick{() dispatch(increment(2))}数值增加/buttonbutton onClick{() dispatch(decrement(5))}数值减少/button/div)
}
总结 任何一个组件都可以直接接入 Redux也就是可以直接1 修改 Redux 状态 2 接收 Redux 状态 并且只要 Redux 中的状态改变了所有接收该状态的组件都会收到通知也就是可以获取到最新的 Redux 状态 这样的话两个组件不管隔得多远都可以直接通讯了
redux数据流动过程 Redux应用
代码结构 /store --- 在 src 目录中创建用于存放 Redux 相关的代码 /actions --- 存放所有的 action /reducers --- 存放所有的 reducer index.js --- redux 的入口文件用来创建 store Redux应用
ActionType Action Type 指的是action 对象中 type 属性的值 Redux 项目中会多次使用 action type比如action 对象、reducer 函数、dispatch(action) 等 目标集中处理 action type保持项目中 action type 的一致性 action type 的值采用domain/action(功能/动作)形式进行分类处理比如 计数器counter/increment 表示 Counter 功能中的 increment 动作 登录login/getCode 表示登录获取验证码的动作 个人资料profile/get 表示获取个人资料
步骤 在 store 目录中创建 actionTypes 目录或者 constants 目录集中处理 创建常量来存储 action type并导出 将项目中用到 action type 的地方替换为这些常量从而保持项目中 action type 的一致性
// actionTypes 或 constants 目录const increment counter/increment
const decrement counter/decrementexport { increment, decrement }// --// 使用// actions/index.js
import * as types from ../acitonTypes
const increment payload ({ type: types.increment, payload })
const decrement payload ({ type: types.decrement, payload })// reducers/index.js
import * as types from ../acitonTypes
const reducer (state, action) {switch (action.type) {case types.increment:return state 1case types.decrement:return state - action.payloaddefault:return state}
} 注额外添加 Action Type 会让项目结构变复杂此操作可省略 ( 大型项目推荐使用 ) 。但domain/action 命名方式强烈推荐
Redux应用
Reducer的分离与合并
随着项目功能变得越来越复杂推荐 使用多个 reducer按照项目功能划分每个功能使用一个 reducer 来处理该功能的状态更新项目中会有多个 reducer但是 store 只能接收一个 reducer因此需要将多个 reducer 合并为一根 reducer才能传递给 store 合并方式使用 Redux 中的 combineReducers 函数 注意合并后Redux 的状态会变为一个对象对象的结构与 combineReducers 函数的参数结构相同 比如此时 Redux 状态为{ a aReducer 处理的状态, b bReducer 处理的状态 } 整个 Redux 应用的状态变为了对象但是对于每个 reducer 来说每个 reducer 只负责整个状态中的某一个值每个reducer只负责自己要处理的状态 合并 reducer 后redux 处理方式只要合并了 reducer不管分发什么 action所有的 reducer 都会执行一次。各个 reducer 在执行的时候能处理这个 action 就处理处理不了就直接返回上一次的状态。所以我们分发的某一个 action 就只能被某一个 reducer 来处理也就是最终只会修改这个 reducer 要处理的状态最终的表现就是分发了 action只修改了 redux 中这个 action 对应的状态
import { combineReducers } from redux// 计数器案例状态默认值为0
const aReducer (state 0, action) {}
// Todos 案例状态默认值为[]
const bReducer (state [], action) {}// 合并多个 reducer 为一个 根reducer
const rootReducer combineReducers({aReducer: aReducer,bReducer: bReducer
})// 创建 store 时传入 根reducer
const store createStore(rootReducer)// 此时合并后的 redux 状态 { a: 0, b: [] }reducer状态合并后再次访问每个状态的时候这个状态就是合并后的对象了需要.上对象访问状态
import { useSelector } from react-reduxconst App () {const count useSelector(state state.aReducer)const list useSelector(state state.bReducer)
}
注释个人针对redux的理解叙述 const increment payload ({ type: increment, payload })redux作为一个状态管理工具将数据的状态分为了三部分action、reducers和storeaction作为一个描述数据用途的对象 { type increment, payload: 10 }这里可以将这个用途对象理解为一个标志increment就是计数器增加的标志表示将来需要增加的标识当我们进行点击行为增加数据的时候会调用store就会调用这个增加的标识store.dispacth(increment())store.dispatch发起状态更新后只要调用了dispatch操作Redux store 内部就会调用 reducer 并且传入上一次的状态和当前传入的 action标识相当于会给reduce分发一个状态标志increment从而使用switch函数进行标识的配对分发正确的逻辑内容,计算出新的状态并返回reducer 执行完毕后将最新的状态交给 storestore 用最新的状态替换旧状态状态更新完 注
redux在这里 createStore 的使用已经过时想要了解数据分发传递的实验过程可以参考上面新的用法逻辑提现在新的文章中...