React新特性,ReactHooks

2019-08-25  本文已影响0人  番茄_tomatoMan

最新在学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。

上一篇下一篇

猜你喜欢

热点阅读