React Hooks
- 有状态的组件没有渲染【hook函数组件返回值不是DOM元素】
- 有渲染的组件没有状态【hook函数组件没有useState存储状态值】
为什么使用hooks
-
useEffect 可以让相同逻辑在同一个地方进行处理【eg:事件的订阅与取消】
-
Hooks 体现了 React 在组件内部进行逻辑隔离,不像 class 组件的 state 可自定义和跨组件重用。
-
可以将组件相同逻辑放置在自定义 hook 中使用【class组件是使用高阶组件 (HOC) 进行逻辑复用的】
hook的使用规则
-
只能在函数最外层调用 hook【不要在循环、条件判断或者子函数中调用】
-
只能在 React 的函数组件中调用 hook【或者在**自定义 hook **中使用】
详情了解见官方文档:https://react.docschina.org/docs/hooks-rules.html
一、useState【状态钩】
const [state, setState] = useState(initState) // 函数返回值state命名可以【任意】命名
-
接受参数: state 的初始值
-
返回值:当前 state 值及异步更新 state 的函数 setState( )
说明:
-
state只在首次渲染是被创建且赋予初始值 initState【该初始值不仅仅局限于对象】
-
useState( ) 函数**可以定义多个,**用来保存相应的状态数据信息
-
调用更新函数 setState( ) 时,函数组件将重新渲染,并赋予 state 最新的值
二、useEffect【效果钩(副作用函数)】
useEffect(() => {}, [param])
- 接受参数:
-
参数1:执行操作逻辑函数
-
参数2:更新 effect 依赖项参数数组
- 可选清除订阅机制:操作逻辑函数返回函数中执行清除操作(见说明第2点)
性能优化:【控制effect的执行(依赖项数组参数)】
-
当依赖项数组未设置时,默认每次渲染会更新后执行 effect
-
当依赖项参数数组为空时,只在初次渲染后执行 effect
-
当 effect 中依赖项参数数组中的值渲染时未发生变化时,则 effect 不会执行更新替换操作
说明:
-
默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候【DOM渲染-调用副作用函数-页面展示最新数据信息】
-
useEffect 可以通过返回一个函数来指定如何“清除”相关的副作用操作,便于将添加和移除订阅的逻辑放在一起
-
每次我们重新渲染,默认都会生成新的 effect,替换掉之前的【避免因没有处理更新逻辑而导致常见的 bug】
-
effect 的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件的时候执行一次
参考链接
三、useContext【很多不同层级的组件需要访问同样一些的数据】
import React from 'react';
const MyContext = React.createContext(defaultValue);
// 外层包裹组件
<MyContext.Provider value={initValue}>
<MyComponents /> // 可以共享MyContext的数据
</MyContext.Provider>
// 函数子组件 MyComponents
import React { useContext } from 'react'
function MyComponents() {
const contextData = useContext(MyContext) // 获取MyContext中的共享数据信息
}
1. 使用 useContext 结合 userReducer 为顶层组件构建一个全局store
// context.js
import React, { createContext } from 'react';
export const Context = createContext();
function reducer(state, action) {
const { type, payload = {} } = action || {};
switch(type) {
case 'search':
return { ...state, params: action.params };
case 'update':
return Object.assign({}, state, payload);
default:
return state;
}
}
export function ContextProvider (props) {
const { state, dispatch } = userReducer(reducer, initialState);
return(
<Context.Provider value={ { state, dispatch } }>
{ props.children }
</Context.Provider>
)
}
// 使用的页面
import React, { useContext } from 'react';
import { Context, ContextProvider } from 'context';
const { state, dispatch } = useContext(Context);
export default function MyPage() {
return (
<ContextProvider>
<MyComponents />
</ContextProvider>
)
}
说明:
-
useContext(MyContext) 只可以帮助我们获取 context 值和订阅 context 的变化,仍然需要在上层组件中使用 Provider 来提供context, 并且多个 Provider 可以相互嵌套使用
-
当 react 渲染订阅了 context 的组件时,该组件会从距离他**最近的 Provider 中获取当前的 context【initValue】**值, 若没有匹配到相应的 Provider 则 defaultValue 生效
-
将 undefined 传递给 Provider 的 value 时,消费组件的 defaulValue 不会生效
-
Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染
四、unstated-next【React轻量状态管理库】(结合 useReducer)
基本使用:
/**
* 1. 使用 createContainer 构建存储容器
**/
import { createContainer } from "unstated-next"
// 定义一个reducer纯函数处理相应逻辑并更新 state
function reducer(state, action) {
switch(action.type) {
case 'add':
return { ...state, propName: action.payload };
default:
return state;
}
}
//
function useLocalStore() {
const [state, dispatch] = useReducer(reducer, initialState);
return {
state,
dispatch
}
}
export default const Store = createContainer(useLocalStore);
/**
* 2. 需使用该 store.Provider 包裹需要使用 store 的使用的组件
*/
import Store from './filePathName';
<Store.Provider>
<Components /> // 需要使用该轻量级仓库的组件
</Store.Provider>
/**
* 3. 在需要的页面中使用
**/
import Store from ‘./filePathName’;
const { state: { initCount }, dispatch } = Store.useContainer();
/**
* 4. 解决多层container嵌套问题
**/
<Container1.Provider>
<Container2.Provider>
<Container3.Provider>
MyApp
</Container3.Provider>
</Container2.Provider>
</Container1.Provider>
**修改为:**
function compose(...containers) {
return function Component(props) {
return containers.reduceRight((children, Container) => {
return <Container.Provider>{children}</Container.Provider>
}, props.children)
}
}
let Provider = compose(Container1, Container2,Container1);
<Provider >
myApp
</Provider>
/**
* 5. useReducer简单内部构建
*/
function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState);
function dispatch(action) {
const nextState = reducer(state, action);
setState(nextState);
}
return [state, dispatch];
}
useReducer(reducer, initialArg, init);
- 指定初始state
useReducer(reducer, { count: initCount });
- initialArg:容器库 initState 对象
- 惰性初始化
useReducer(reducer, initCount, function(initCount) { return {count: initCount} })
-
initialArg:init 函数的参数值
-
init 函数:可以用于对初始数据信息执行一些逻辑操作
function reducer(state, action) {
const { payload = {} } = action || {};
return {
...state,
...payload,
}
}
const [query, setQuery] = useReducer(reducer, {
pageNo,
pageSize,
createAt,
...
})
// 使用时
setQuery({ payload: { …query, pageNo:_pageNo } })
说明:
-
React 会确保 dispatch 函数的标识是稳定的,并且不会在组件重新渲染时改变
-
当 Reducer Hook 的返回值与当前 state 相同,React 将跳过子组件的渲染及副作用的执行
参考链接
五、 useCallback(主要用于处理对于一些数据更新引起其他组件不必要的渲染)
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
-
返回值:返回一个memoized回调函数
-
接受参数:
-
参数1::内联函数
-
参数2:依赖项数组
说明:
-
只有当依赖项发生改变时,内联回调函数中的值才会得到最新值。否则,内联回调函数中的变量都是之前时侯的值。
-
当传入空数组时,该返回的memoized回调函数一直不会发生改变。
参考链接
六、useMemo【优化避免在每次渲染时都进行高开销的计算逻辑】
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
-
返回值:返回一个memoized值
-
接受参数:
-
参数1::“创建”函数
-
参数2:依赖项数组
说明:
-
若没有提供依赖项,useMemo在每次渲染时都会计算新的值
-
若提供依赖项数组,当某个依赖项改变时才会重新计算memoized值
-
不要在该“创建”函数内部执行与渲染无关的操作【如副操作等适合使用在其它hook中的逻辑】
七、useRef
const refContainer = useRef(initialValue);
-
返回值:返回一个可变的 ref 对象,返回的该 ref 对象在组件的整个生命周期内保持不变
-
返回可变的ref对象的 current 属性初始化值为 useRef 传入的参数值(initialValue)
作用:
-
获取组件实例对象或DOM对象
-
可以跨渲染周期保存数据
说明:
-
当 ref 对象内容发生变化时,useRef 并不会通知你
-
变更 .current 属性不会引发组件重新渲染
-
想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现
React.forwardRef
具体实例参考链接
八、useImperativeHandle【避免暴露过多属性给父组件】
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
useImperativeHandle(ref, createHandle, [deps])
- 接受参数:
-
参数1: 接收一个通过forwardRef引用父组件的ref实例
-
参数2:回调函数,返回一个对象,对象里面存储需要暴露给父组件的属性或方法
说明:
-
官方建议 useImperativeHandle 应当与 forwardRef 一起使用,避免使用 ref 那样的命令式代码
-
当我们不想向父组件暴露太多的东西的时候,可以使用 useImperativeHandle 来按需暴露给父组件一些东西
九、useLayoutEffect【**在所有的 **DOM 变更之后同步调用 effect】
什么情况下使用:
说明:
-
在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新
-
建议尽可能使用标准的 useEffect 以避免阻塞视觉更新
十、useDebugValue 【在react的浏览器调试工具上显示你的自定义hooks,或者给hooks标记一些东西】
useDebugValue(value[, callback]);
接受参数:
-
参数1:参数标记在react的调试工具上
-
参数2:回调函数,函数形参为useDebugValue的第一个参数,返回值会显示在浏览器调试工具中【回调函数中可以进行一系列操作】
各hook的具体实例理解可以参考下面???
参考链接
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!