最新在学ReactHooks这个新特性,把学习笔记记下来,供大家分享。
原先的函数组件是没有生命周期函数的,这样在使用函数组件时就会觉得没有类组件用的那么得心应手,在React16.9时,React官方出现了ReactHook这个语法糖,这个语法糖主要就是解决函数组件中没有生命周期函数的问题。
一、useStates
useState是让React函数组件能够使用state
基本用法如下:
const [ state, setState ] = useState( initState );
1、state是你要设置的状态
2、setState是你要更新状态的方法,命名随意
3、initState为最初的state,可以是任意的数据类型,也可以是回调函数,但是必须有返回值
二、useEffect
数据获取、订阅、或手动修改React DOM这些行为都可以称之为副作用,useEffect正是用来处理这些副作用的。
同时useEffect也是componentDidMount、componentDidUpdata、component WillUnMount这几个生命周期的统一。
基本用法如下:
useEffect( callback, array)
1、callback回调函数用来处理副作用逻辑,另外可以返回一个函数用于清除工作,类似于componentWillUnMount
2、array可选,一个数组,用来控制执行,当array为空数组时,在render之后执行,相当于componentDidMount,只执行一次,当没有array时,每次render触发后都会执行,当array内存在值时,会在数组发生改变后执行
useEffect有两种清理机制
React有两种副作用,一种是需要清理的,一种是不需要清理的。
1、网络清除、DOM修改、日志记录等这些都是不需要清除的。useEffect会自动处理
2、订阅和取消订阅,事件监听和取消事件监听,这种是需要清理的
下面是useEffect清理机制:
1、useEffect在每次执行之前都会自动清理之前的effect
2、effect可以返回一个函数用于清理工作
三、useContext
useContext是为了方便我们使用context而提出的API
context
context是React提供数据共享的一种API,它可以解决需要通过多层嵌套传递props的问题。
主要通过以下三种形式:
1、通过React.createContext( )创建Context函数
2、使用Context.Provider包裹组件,给他的后代组件提供数据
3、Context.Provider所有的后代组件,都可以通过Context.Consumer获取Context的数据
下面是context的一个使用案例:
1、创建Context
const context = React.creatContext( );
2、使用Context.Provider包裹组件
<Context.Provider value={store}>
<MyComponent />
</Context.Provider>
3、使用Context.Consumer获取共享数据
// MyComponent
<Context.Consumer>
{
valve => {
// value就是通过context共享过来的数据,这里是store
}}
</ Context.Consumer>
通过以上方法来使用context是非常麻烦的,所以hooks提供了useContext方法
useContext( context )
useContext( context )是针对context提供的一个API,它接受React.creatContext( )的返回值作为参数,也就是context的对象,并返回最近的context
使用useContext将不再需要Previder和Consumer
当最近的context更新时,那么使用该context的hook将会重新渲染
基本使用
const Context = React.creatContext( { loading: false, name: ‘jack’ } );
const OnePage = ()=> {
const ctx = useContext( Context );
return (
<div>
{ ctx.loading && ‘Loading...’ }
</ div>
)
}
四、useReducer 复杂的状态管理
useReducer时useState的变体,用于处理复杂的状态管理
useReducer可以作为useState的一种替代的方案,它的灵感来自于redux的reducer
基本使用
useReducer主要接受三个参数,下面是useReducer的基本用法:
// useState的基本方法
const [ state, setState ] = useState( initState );
// useReducer的基本方法
const [ state, dispatch ] = useReducer( reducer, initState, initialAction );
参数:
1、reducer是一个函数,用于处理action更新state
2、initialState为初始的state
3、initialAction为useReducer初始执行时被处理的action
返回值:
1、state为状态
2、dispatch为更新state的方法,它接受action作为参数
如何用useReducer更新state?
只需要调用dispatch( action )方法即可更新state
dispatch用于更新state,当dispatch( action )被调用时,reducer方法也会被调用,并会根据action的描述去更新state。
reducer参数详解
在了解参数reducer之前,我们先来了解action是什么:
1、action
action是一种动作的描述,描述你发出的这个动作它应该做的事。
action本质是一个对象(object),它通常有一个type属性,用于描述该如何更新state,此外你还可以携带其他参数
下面是action的一个例子:
const action = {
type:’ increment ’, // 增量表示该state的值要增加
payload:{
other:’ value ’ // 携带的其他参数
}
}
我们该如何把描述性的action转化为最新的state?这就是reducer所做的事情了。
2,reducer
reducer是redux的产物,它本质上是一个函数,主要用于处理action,并它返回最新的state。
总的来说,reducer是action和state的转换器,它根据action的描述,去更新state。
它的结构如下:
(state, action) => newState
下面是reducer的一个应用案例:
const initialState = { count: 0 }; // 初始state
const reducer = (state,action) =>{
// 变量action,更加action的描述去更新state
switch (action.type) {
// 当type为reset时,重置state的值,让state等于初始state
case 'reset': return initialState;
// 当type为increment时,让count加一
case 'increment': return {count: state.count + 1};
// 当type为decrement时,让count减一
case 'decrement': return {count: state.count - 1};
// 当type不属于上面任何一个时,不做任何更改,返回当前的state
default: return state;
}
}
const MyCompoent = () =>{
const [state, dispatch] = useReducer(reducer, initialState);
return (
当前count的值为:{ state.count }
dispatch({ type: 'reset' }) } >重置
dispatch({ type: 'increment' }) } >加一
dispatch({ type: 'decrement' }) } >减一
)
}
结合useContext
useContext可以解决组件间的数据共享的问题,而useReducer则解决了复杂状态管理的问题,因此把他们结合起来之后,我们就可以实现redux的功能了。那也意味着我们可以不再依赖第三方状态管理器。
五、额外的Hooks
* useMemo
* useCallback
* useRef
1、useMemo
useMemo是一个用于性能优化的API,它通过记忆值手段让你避免在每个渲染上执行高开销的计算,可减少渲染的耗时。
尤其适合用在需要复杂计算的场景,比如复杂的列表渲染,对象深拷贝等等。
基本用法
const memoizedValue = useMemo(callback,array);
1,callback: 一个函数,用于处理你的计算逻辑。
2,array: 一个数组,当数组发生改变时useMemo才会重新执行。
useMemo的返回值是一个记忆值,它是callback的返回值。
useMemo只会在数组发生变化时才会重新计算memoized(记忆)值。这样的优化有助于避免在每个渲染上进行昂贵的计算。
下面是一个用例:
// useMemo只会在obj1或obj2发生改变时才会重新执行。
const obj1 = { id:"12", name:"jack" };const obj2 = { id:"14", name:"ben", age:23 };
const memoizedValue = useMemo(()=>Object.assign(obj1,obj2),[obj1,obj2]);
// 使用<div> { memoizedValue.name } </div>
注意:不要在useMemo里面处理副作用的逻辑,副作用应该放在useEffect内处理。
2、useCallback
useCallback和useMemo一样,都是用于性能优化的API。
基本用法
const memoizedCallback = useCallback(callback,array);
1,callback: 一个函数,用于处理你的计算逻辑。
2,array: 一个数组,当数组发生改变时useCallback才会重新执行。
useCallback 和 useMemo 类似,它们的返回值都是记忆化的。但是会有一些不同,useMemo的返回值就是callback的返回值,而useCallback的返回值则callback函数本身。
useCallback(fn, inputs) 等价于 useMemo(() => fn, inputs)。
下面是useCallback一个案例:
const obj1 = { id:"12", name:"jack" };const obj2 = { id:"14", name:"ben", age:23 };
const memoizedFn = useCallback(()=>Object.assign(obj1,obj2),[obj1,obj2]);
// 使用<div>{ memoizedFn().name }</div>
它相当于useMemo的这种写法:
const obj1 = { id:"12", name:"jack" };const obj2 = { id:"14", name:"ben", age:23 };
const memoizedFn = useMemo(()=>{
return ()=>{
return Object.assign(obj1,obj2)
}},[obj1,obj2]);
// 或const memoizedFn = useMemo(()=>()=>Object.assign(obj1,obj2),[obj1,obj2]);
// 使用<div>{ memoizedFn().name }</div>
3、useRef
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数(initialValue)。
基本用法:
const MyComponent = () =>{
// 1,创建ref
const inputEl = useRef(null);
const onInput = () =>{
// 3,访问ref
console.log(inputEl.current.value)
}
// 2,挂载ref
return (
<div>
<input ref={ inputEl } type="text" />
<p>
<button onClick={ onInput } > 获取input的值 </button>
</p>
</div>
)}
六、自定义hooks
自定义的hooks是一个 JavaScript 函数,其名称以 use 开头,函数内可以调用其他 Hook。
主要就是利用react hooks封装成一个具有特定逻辑的,或可重用的函数。
下面是官方的一个案例,查询指定用户是否在线:
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
// 订阅
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
// 组件卸载时取消订阅
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;}
案例应用:
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';}
七、hooks的规则
Hooks 是 JavaScript 函数,但在使用它们时需要遵循一些规则。
只在顶层调用Hooks
尽量在顶层作用域中调用Hooks。
不要在循环,条件或嵌套函数中调用Hook,否则可能会无法确保每次组件渲染时都以相同的顺序调用Hook。
只在函数组件中调用Hooks
React Hooks目前只支持函数组件,因此你不能在class组件中调用它API,但你可以在class组件内调用react hooks组件。
下面是React Hooks的应用场景:
1,函数组件
2,自定义hooks (在自定义的hooks中调用hooks)
在未来,react官方计划将React Hooks 拓展到class组件,到时候class组件也能使用React Hooks。
网友评论