React Hooks 你不来了解下?

前言

最近在看 React 的新语法—— React Hooks,只能一句话归纳:React 语法真的是愈来愈强大,越写代码越少。html

强烈推荐还没看 React Hooks 的同窗去学习下,这会让你写react 项目变得很是爽!react

之前 React 组件能够当作是: 无状态组件(function定义)和有状态组件(class 定义),React Hooks 出现以后,咱们基本全部的组件均可以用function定义,包括有组态组件,基本废除了 写 class 语法的 复杂性,让咱们写代码真正变成了函数式编程。git

状态 Hooks(useState)

这里说明一点,react中全部的Hooks都是一种函数,函数都是用来实现特定功能的。github

useState 提供了建立组件state的功能,用法:web

const [count, setCount] = useState(0)
复制代码

useState() 接受惟一一个状态初始值参数,返回包含状态和改变状态对应的函数的数组,这里采用 数组解构方法得到 状态变量 count ,改变状态方法 setCount。ajax

强调一点:编程

useState() 传入的初始值不必定非要是个对象,能够为普通数据类型,好比:Number,String等,初始值用做组件初次渲染。redux

setCount() 接受一个全新的state状态,react会直接所有替换掉原来的state状态,这点和 setState() 有所不一样。数组

Example:浏览器

import React, { useState } from 'react';
function Example(){
  const [ count , setCount ] = useState(0);
  return (
    <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>click me</button> </div>
  )
}
export default Example;

复制代码

当把 Example 组件渲染到页面上时,能够经过点击按钮实时改变 count 状态,react 也会根据状态改变从新渲染页面。

执行反作用操做Hooks(useEffect)

以前在写 react 组件时,每每咱们在组件的生命周期函数里面作一些额外的操做,好比发送ajax请求获取数据,清除定时器和异步执行任务等。

咱们发现这样操做重复的代码不少,并且若是对于 react 生命周期钩子不熟悉的话,很容易出错,因而乎,useEffect() Hooks 出现了。

useEffect() hooks 能够容许咱们在 react 函数式组件中执行一些额外的反作用操做。

在 React 组件中有两种常见反作用操做:

  • 须要清除的,好比开启的定时器,订阅外部数据源等,这些操做若是在组件消亡后不及时清除会致使内存泄漏。

  • 不须要清除的,好比发起网络请求,手动变动 DOM,记录日志等。

在 react 官网中有一段话很重要:

若是你熟悉 React class 的生命周期函数,你能够把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

Example:

import React, { useState , useEffect } from 'react';
function Example(){
  const [ count , setCount ] = useState(0);
  useEffect(()=>{
    console.log(`You clicked ${count} times`)
  })
  return (
    <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>click me</button> </div>
  )
}
export default Example;
复制代码

咱们在刚才的例子上新增了一个功能,每次咱们 count 状态改变的时候都会在控制台打印出咱们点击的次数。能够看到使用 useEffect() Hooks 轻松实现。

强调一点:

  • react首次渲染和以后的每次渲染都会调用一遍useEffect函数,而以前咱们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新致使的从新渲染(componentDidUpdate)。

  • useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数是异步执行的,而componentDidMonut和componentDidUpdate中的代码都是同步执行的。

  • 能够为 useEffect() 传入第二个参数,它是一个数组,数组里面表示这个反作用的操做依赖的状态变量,换句话说:若是这个反作用的操做依赖的状态变量没有改变,则不会执行反作用操做。

组件之间传值Hooks(useContext)

以前在用类声明组件时,父子组件的传值是经过组件属性和props进行的,那如今使用方法(Function)来声明组件,已经没有了constructor构造函数也就没有了props的接收,那父子组件的传值就成了一个问题。React Hooks 为咱们准备了useContext。

useContext它能够帮助咱们跨越组件层级直接传递变量,实现共享。

Example:

一:利用 createContext 建立上下文

import React, { useState , createContext } from 'react';

// 建立一个 CountContext
const CountContext = createContext()

function Example(){
  const [ count , setCount ] = useState(0);
  return (
    <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>click me</button> {/* 将 context 传递给 子组件,context 值由value props决定*/} <CountContext.Provider value={count}> <Counter/> </CountContext.Provider> </div> ) } export default Example; 复制代码

二:使用useContext 获取上下文

对于要接收context的后代组件,只需引入 useContext() Hooks 便可。

function Counter(){
  const count = useContext(CountContext)  //一句话就能够获得count
  return (<h2>{count}</h2>)
}
复制代码

强调一点:

useContext 的参数必须是 context 对象自己:

  • 正确: useContext(MyContext)
  • 错误: useContext(MyContext.Consumer)
  • 错误: useContext(MyContext.Provider)

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 <MyContext.Provider> 的 context value 值。

处理更为复杂state结构的Hooks(useReducer)

前面咱们使用的 useState Hooks能够为组件提供 state和操做改变state状态的方法,但每每有时候咱们的state 结构更为复杂,例如 state 包含多个子值,或者下一个 state 依赖于以前的 state 等,这时候 useReducer 比 useState 更合适。

useReducer 的用法:

const [state, dispatch] = useReducer(reducer, initialArg, init);
复制代码

useReducer 接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

咱们可使用 useReducer 来从新写咱们开篇计数器的demo:

Example:

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      return state
  }
}
// 定义 Counter 组件
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div> Count: {state.count} <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </div>
  );
}

复制代码

对于熟悉 redux 的伙伴,这种写法很容易就能理解,每次经过点击按钮分发一个action来更新state状态数据。

强调一点:

React 不使用 state = initialState 这一由 Redux 推广开来的参数约定。有时候初始值依赖于 props,所以须要在调用 Hook 时指定。若是你特别喜欢上述的参数约定,能够经过调用 useReducer(reducer, undefined, reducer) 来模拟 Redux 的行为,但咱们不鼓励你这么作。

这里是 react 官网提供的一句话,也就是说咱们为 state 提供初始值的时候不可以像 redux 中利用 ES6 默认参数来指定,必须得经过 useReducer来指定。这个切记,由于我也踩过坑!

对于 useReducer 和 useState的区别主要是如下两点:

  • 当 state 状态值结构比较复杂时,使用 useReducer 更有优点。
  • 使用 useState 获取的 setState 方法更新数据时是异步的;而使用 useReducer 获取的 dispatch 方法更新数据是同步的。

性能优化Hooks(useMemo)

咱们知道 使用class 形式的组件有着生命周期 shouldCompnentUpdate函数用来优化组件的性能,防止每次渲染形成昂贵的开销。 使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新以前)这个生命周期,也就是说咱们没有办法经过组件更新前条件来决定组件是否更新。并且在函数组件中,也再也不区分mount和update两个状态,这意味着函数组件的每一次调用都会执行内部的全部逻辑,就带来了很是大的性能损耗。

useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。

举个例子:

在 A 组件中有两个子组件 B 和 C,当 A 组件中传给 B 的 props 发生变化时,A 组件状态会改变,从新渲染。此时 B 和 C 也都会从新渲染。其实这种状况是比较浪费资源的,如今咱们就可使用 useMemo 进行优化,B 组件用到的 props 变化时,只有 B 发生改变,而 C 却不会从新渲染。

Example:

// A 组件

import React from 'react';

export default ({ text }) => {
  console.log('component A:', 'render');
  return <div> A 组件:{ text }</div>
}

// B 组件

import React from 'react';

export default ({ text }) => {
  console.log('component B:', 'render');
  return <div> B 组件:{ text }</div>
}

// App 组件

import React, { useState, useMemo } from 'react';
import A from './ExampleA';
import B from './ExampleB';

export default () => {
  const [a, setA] = useState('A');
  const [b, setB] = useState('B');

  const exampleA = useMemo(() => <A text={a} />, [a]);
  const exampleB = useMemo(() => <B text={b} />, [b]);

  return (
    <div> { exampleA } { exampleB } <br /> <button onClick={ () => setA('A改变了') }>修改传给 A 的属性</button> &nbsp;&nbsp;&nbsp;&nbsp; <button onClick={ () => setB('B改变了') }>修改传给 B 的属性</button> </div>
  )
}
复制代码

咱们点击不一样的按钮,控制台都只会打印一条输出,改变 a 或者 b,A 和 B 组件都只有一个会从新渲染。

其实 React 还有不少经常使用的 Hooks,好比用来获取DOM元素 和保存变量的useRef,优化函数式组件性能的useCallback等,对于这些的Hooks你们能够去react 官网了解下,相信你们应该也能搞清楚,这里就不作进一步探讨。

React Hooks Api

结语

本篇文章出自于咱们 web-study 仓库,若是喜欢的话,欢迎给个 star!

地址: web-study

相关文章
相关标签/搜索