React Hooks学习

React Hooks

github地址代码调试地址

一.React Hooks的作用

  • 对函数组件进行增强
  • 让函数型组件可以存储状态
  • 可以拥有处理副作用的能力
  • 实现类组件相同的功能

二.类组件的不足之处

  • 缺少逻辑复用的机制

    • 为了复用逻辑增加无实际渲染效果的组件,增加了组件层级,显示十分臃肿,增加了调试的难度以及运行效率的降低
  • 类组件经常会变得很复杂难以维护

    • 将一组相干的业务逻辑拆分到了多个生命周期函数中,在一个生命周期函数内,存在多个不相干的业务逻辑
  • 类成员方法不能保证 this 指向的正确性

三.Hooks API的使用

useState

  • 因为组件是单向数据流 useState主要是提供参数缓存
  • useState接受唯一的参数即状态初始值,初始值可以是任意数据类型
  • useState返回值为数组,数组中存储值和更改状态值的方法,方法名称约定以 set 开头,后面加上状态名称。
  • useState方法可以被调用多次,用以保存不同状态值
  • useState只在第一次渲染的时候执行一次,参数可以是函数,只会被调用一次
  • 设置状态值方法的参数可以是一个值也可以是一个函数,设置状态值的方法是异步的

使用

import {
     useState} from 'react'

function App() {
     
  const [count, setCount] = useState(0)
  return (
    <div>
      <span>{
     count}</span>
      <button onClick={
     ()=>setCount(count+1)}> + 1</button>
    </div>
  );
}

export default App;

useReducer

  • useReducer 是另一种让函数组件保存状态的方式,可以将 dispatch 传给子组件使用
import {
      useReducer } from "react";
function App() {
     
  // useReducer => 提供redux
  function reducer (state,action){
     
    switch (action.type) {
     
      case 'increment':
        return state+1
      case 'decrement':
        return state-1
      default:
        return state;
    }
  }
  const [countState ,dispatch] = useReducer(reducer,0)
  return (
    <div className="App">
      <span>{
     countState}</span>
      <button onClick={
     ()=>dispatch({
     type:'increment'})}>+1</button>
      <button onClick={
     ()=>dispatch({
     type:'decrement'})}>-1</button>
    </div>
  );
}
export default App;

useContext

  • createContext 方便跨组件层级传值
  • useContext 简化接收传值组件的代码
import {
      createContext,useContext } from "react";
function App() {
     
  // createContext 方便跨组件层级传值
  // useContext 简化接受传值组件的代码
  const countContext = createContext();

  function Foo () {
     
    const value = useContext(countContext)
    return  <div>{
     value}</div>
    // 
    //   {
     
    //     value => {
     
    //       return 
{value}
// } // } // } return ( <div className="App"> <countContext.Provider value={ 100}> <Foo /> </countContext.Provider> </div> ); } export default App;

useEffect

作用

  • 让函数型组件拥有处理副作用的能力,类似生命周期函数
    • componentDidMount:组件挂载完成;
    • componentDidUpdate:组件更新完成;
    • componentWillUnmount:组件将要卸载

使用

  • useEffect(() => {}) :组件挂载完成, 组件更新完 执行
  • useEffect(() => {}, []) :组件挂载完成 执行
  • useEffect(() => () => {}) :组件更新完,组件将要卸载 执行
  • useEffect(() => () => {},[]) :组件将要卸载 执行
  • useEffect(() => {}, [xxx]):只有指定数据发生变化时触发 effect
  • useEffect 函数如果有返回那一定是一个清理资源的函数(准备卸载组件了,还不清就来不及了),如果是异步函数就变成了返回 Promise.
  // useEffect 异步函数的使用
  function getData (){
     
    return new Promise((resolve)=>{
     
      resolve(100)
    })
  }
  // 可以
  useEffect(()=>{
     
    getData().then(result=>{
     
      console.log(result)
    })
  },[])

// 添加函数自执行 使用异步函数
  useEffect(()=>{
     
    (async function(){
     
      const result = await getData();
      console.log(result)
    })()
  },[])

useMemo和memo

作用

  • useMemo 类似 Vue 中的计算属性,可以检测某个值的变化,根据变化只计算新值
  • useMemo 会缓存计算结果,如果检测子没有发生变化,即使组建重新渲染,也不会重新计算,此行为可以有助于避免在每个渲染上进行昂贵的计算
  • memo 性能优化,如果本组件中的数据没有发生变化,阻止组件更新,类似类组件中的 PureComponent 和 shouldComponentUpdate

使用

import {
     useState, useMemo,memo } from "react";
function App() {
     
  const [countEf,setCountEf] = useState(1);
  const compute = useMemo(()=>{
     return countEf*2},[countEf])
  return (
    <div className="App">
      <span>计算属性{
     compute}<Child></Child></span>
    </div>
  );
}
// memo 没有状态更新不让子组件渲染
const Child = memo(function Child() {
     
  console.log('Child组件重新渲染了')
  return <div>我是Child组件</div>
})
export default App;

useCallback

作用

  • 性能优化,缓存函数,使用组件重新渲染时得到相同的函数实例。否则每次父组件渲染,函数变量的实例都会变化,导致里层组件被重新渲染

使用

export default function App () {
     

  const [count, setCount] = useState(0)
  const resetCount = useCallback(() => {
     
    setCount(0)
  }, [setCount])

  return (
    <div>
      <span>{
     count}</span>
      <button onClick={
     () => setCount(count + 1)}> + 1</button>
      <Foo resetCount={
     resetCount} />
    </div>
  )
}

useRef

作用

  • 获取DOM元素对象
import {
      useRef } from "react";

export default function App () {
     
  const box = useRef()
  return (
    <div ref={
     box}>
      <button onClick={
     () => console.log(box)}> DIV </button>
    </div>
  )
}
  • 保存数据(跨组件周期)
    • 即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染。
import {
      useRef, useState, useEffect} from "react";

export default function App () {
     
  const [count, setCount] = useState(0)
  let timeId = useRef() // 夸组件生命周期
  useEffect(() => {
     
    // 使用这个 ref 的 current 属性存储数据
    timeId.current = setInterval(() => {
     
      setCount(count => count + 1)
    }, 1000);
  }, [])

  const stopCount = () => {
     
    console.log(timeId.current)
    clearInterval(timeId.current)
  }

  const box = useRef()
  return (
    <div ref={
     box}>
      <span>{
     count}</span>
      <button onClick={
     () => stopCount()}> 停止 </button>
    </div>
  )
}

自定义 Hook

概念

  • 自定义 Hook 是标准的封装和共享逻辑的方式
  • 自定义 Hook 是一个函数,其名称以 use 开头
  • 自定义 Hook 其实就是逻辑和内置 Hook 的组合

使用

// 基本用法
import {
      useState, useEffect} from "react";
import axios from "axios";

function useGetPost () {
     
  const [post, setPost] = useState({
     })
  useEffect(() => {
     
    axios.get('https://jsonplaceholder.typicode.com/posts/1')
    .then((response) => {
     
      setPost(response.data)
    })
  }, [])
  return [post, setPost]
}

export default function App () {
     
  const [post, setPost] = useGetPost()
  return (
    <div>
      <h1>{
     post.title}</h1>
      <div>{
     post.body}</div>
    </div>
  )
}
// 封装公共逻辑
import {
      useState} from "react";

function useUpdateInput (initialState) {
     
  const [value, setValue] = useState(initialState)
  return {
     
    value,
    onChange: e => setValue(e.target.value)
  }
}
export default function App () {
     
  const usernameInput = useUpdateInput('')
  const passwordInput = useUpdateInput('')

  const submitForm = event => {
     
    event.preventDefault();
    console.log(usernameInput.value)
    console.log(passwordInput.value)
  }
  return (
    <form onSubmit={
     submitForm}>
      <input type="text" name="username" {
     ...usernameInput} />
      <input type="password" name="password" {
     ...passwordInput} />
      <input type="submit" />
    </form>
  )
}

React 路由 Hooks

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router } from "react-router-dom";
import App from './App';

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById('root')
);
// home.js
import {
      useHistory, useLocation, useRouteMatch, useParams } from "react-router-dom";

export default function Home(props) {
     
  console.log(props)
  console.log(useHistory())
  console.log(useLocation())
  console.log(useRouteMatch())
  console.log(useParams())
  return  <div>
    <h1>Home works</h1>
  </div>;
}
// list.js
export default function List(props) {
     
  console.log(props)
  return  <div>
    <h1>List works</h1>
  </div>;
}

// app.js
import {
      Link, Route } from "react-router-dom";
import Home from './pages/Home'
import List from './pages/List'

export default function App () {
     
  return (
    <>
      <div>
        <Link to="/home/zhangsan">首页</Link>
        <Link to="/list">列表页</Link>
      </div>
      <div>
        <Route path="/home/:name" component={
     Home} />
        <Route path="/list" component={
     List} />
      </div>
    </>
  )
}

你可能感兴趣的:(React,Hooks)