React Hooks

React Hooks 是⽤来做什么的
  • 对函数型组件进⾏增强, 让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒
  • 让开发者在不使⽤类组件的情况下, 实现相同的功能.
类组件的不足
  1. 缺少逻辑复⽤机制

    为了复⽤逻辑增加⽆实际渲染效果的组件,增加了组件层级 显示⼗分臃肿

    增加了调试的难度以及运⾏效率的降低

  2. 类组件经常会变得很复杂难以维护

    将⼀组相⼲的业务逻辑拆分到了多个⽣命周期函数中

    在⼀个⽣命周期函数内存在多个不相⼲的业务逻辑

  3. 类成员方法不能保证this指向的正确性

Hooks使用

Hooks 意为钩⼦, React Hooks 就是⼀堆钩⼦函数, React 通过这些钩⼦函数对函数型组件进⾏增强, 不同的钩⼦函数提供了不同的功能.

钩子函数
  • useState()

    用于为函数组引入状态

    import React, { useState } from 'react'
    
    function App(props) {
    const [count, setCount] =useState(()=>{
     return props.count || 0;
    })
    const [ person, setPerson]=useState({name: '张三', age: 20})
    return (
    <div>
      <span>{count} {person.name} {person.age}</span>
      <button onClick={()=>{setCount(count+1)}}>+</button>
      <button onClick={()=>{setPerson({...person,name: '李四'})}}> 修改</button>
    </div>
    );
    }
    
    export default App;
    
    
    1. 接收唯⼀的参数即状态初始值. 初始值可以是任意数据类型

    2. 返回值为数组. 数组中存储状态值和更改状态值的⽅法. ⽅法名称约定以set开头, 后⾯加上状态名称

    3. ⽅法可以被调⽤多次. ⽤以保存不同状态值

    4. 参数可以是⼀个函数, 函数返回什么, 初始状态就是什么, 函数只会被调⽤⼀次, ⽤在初始值是动态值的情况.

  • useEffects()

    设置状态值方法的参数可以是一个值也可以是一个函数

    设置状态值方法的方法本身是异步的

  • useReducer()

    userReducer是另一种让函数组件保存的方式

    import React, { useReducer } from 'react'
    
    function App() {
    function reducer(state, action){
     switch (action.type) {
       case 'increment':
         return state + 1;
       case 'decrement':
         return state - 1;
       default:
         return state;
     }
    }
    const [ count, dispatch ]=useReducer(reducer,0)
    return (
     // setcount
    <div>
     <button onClick={() => dispatch({type: 'increment'})}>+</button>
     <span>{count}</span>
     <button onClick={() => dispatch({type: 'decrement'})}>-</button>
    </div>
    );
    }
    
    export default App;
    
    
  • useRef()

    • 获取DOM元素对象
    import React, { useRef } from 'react';
    
    function App() {
      const box = useRef();
      return <div ref={box}>
        <button onClick={()=>{ console.log(box)}}>获取div</button>
      </div>
    }
    
    export default App;
    
    • 保存数据(跨组件周期)

      • 即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染
      import React, { useState, useEffect, useRef } from 'react';
      
      function App() {
        const [count, setCount] = useState(0);
        let timeId = useRef();
        useEffect(()=>{
           timeId.current = setInterval(()=>{
            setCount(count => count + 1)
          }, 1000)
        }, [])
        const stopCount = () =>{
          console.log(timeId)
          clearInterval(timeId.current)
        }
        return <div>
          <span>{count}</span>
          <button onClick={stopCount}>stop</button>
        </div>
      }
      
      export default App;
      
  • useCallback()

    性能优化,缓存函数,使组件重新渲染时得到相同的函数实例

    import React, { useState, memo, useCallback } from 'react';
    
    function App() {
    const [count,setCount] = useState(0);
    const resetCount= useCallback(()=>setCount(0),[setCount])
    return <div>
     <span>{count}</span>
     <button onClick={() => setCount(count + 1) }>+</button>
     <Foo resetCount={resetCount}/>
    </div>
    }
    
    // 避免重新渲染
    const Foo = memo(function Foo (props) {
    console.log('Foo组件重新渲染')
    return <div>
     我是Foo组件
     <button onClick={props.resetCount}>resetCount</button>
     </div>
    })
    
    
    export default App;
    
  • useContext()

    在跨组件层级获取数据时简化获取数据的代码

    import React, { createContext, useContext } from 'react'
    
    const countContext = createContext();
    
    function App() {
    return <countContext.Provider value={100}>
     <Foo />
    </countContext.Provider>;
    }
    function Foo () {
    // 简化获取数据时的代码
    const value = useContext(countContext)
    // 以前的写法  
    // return <countContext.Consumer>
    //   {
    //     value =>{
    //       return <div>{value}</div>
    //     }
    //   }
    // </countContext.Consumer>
    return <div>我的测试数据{value}</div>
    }
    
    export default App;
    
    
  • useMemo()

    • useMemo 的⾏为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值

    • useMemo 会缓存计算结果. 如果监测值没有发⽣变化, 即使组件重新渲染, 也不会重新计算. 此⾏为可以有助于避免在每个渲染上进⾏昂贵的计算.

  • useEffect()

    一、让函数组件拥有处理副作用的能力、类似生命周期函数

    1. useEffect 执⾏时机

      可以把 useEffect 看做 componentDidMount, componentDidUpdate 和 componentWillUnmount 这三个函数的组合.

      useEffect(() => {}) => componentDidMount, componentDidUpdate

      useEffect(() => {}, []) => componentDidMount

      useEffect(() => () => {}) => componentWillUnMount

      import React, { useState, useEffect } from 'react'
      import ReactDom from 'react-dom'
      
      function App() {
        const [count, setCount] = useState(0);
        // 组件挂载完成之后执行  组件数据更新完成之后执行
        // useEffect(() => {
        //   console.log(1)
        // })
        // 组件挂载完成之后执行
        // useEffect(()=>{
        // console.log(123)
        // },[])
        //  组件被卸载之前执行
        useEffect(()=>{
          return () =>{
            console.log('组件被卸载了')
          }
        })
        return <div>
          <span>{count}</span>
          <button onClick={() => setCount(count + 1)}>+</button>
          <button onClick={() => ReactDom.unmountComponentAtNode(document.getElementById('root'))}>卸载组件</button>
        </div>;
      
      }
      // function useEffectApp() {
      //  return <div>ssssss</div>
      // }
      
      export default App;
      

      二、useEffect使用方法

      1. 为window对象添加滚动事件

      2. 设置定时器让count数值每隔⼀秒增加

        import React, { useEffect, useState } from 'react';
        import ReactDOM from 'react-dom'
        
        function App() {
          function onScroll () {
            console.log('页面发生滚动了')
          }
          useEffect(() => {
            window.addEventListener('scroll', onScroll)
            return () =>{
              window.removeEventListener('scroll', onScroll)
            }
          }, [])
        
          const [count,setCount] = useState(0);
        
          useEffect(()=>{
           const timeId = setInterval(()=> {
              setCount(count=>{
                document.title = count + 1;
                return count +1
              })
           },1000)
           return () =>{
             clearInterval(timeId)
           }
          }, [])
          return <div>
            <span>{count}</span>
            <button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>卸载组件</button>
          </div>
        }
        
        export default App;
        

        三、useEffect 解决的问题

        1. 按照⽤途将代码进⾏分类 (将⼀组相⼲的业务逻辑归置到了同⼀个副作⽤函数中)
        2. 简化重复代码, 使组件内部代码更加清晰

        四、只有指定数据发⽣变化时触发effect

          useEffect(() => {
            document.title = count
          }, [count])
        

        五. useEffect 结合异步函数

        useEffect中的参数函数不能是异步函数, 因为useEffect函数要返回清理资源的函数, 如果是异步函数就变成了返回Promise

          useEffect(() => {
           (async function() {
            let response = await getData();
            console.log(response)
           })()
        
  • ​ memo方法

    性能优化, 如果本组件中的数据没有发⽣变化, 阻⽌组件更新. 类似类组件中的 PureComponent 和 shouldComponentUpdate

    import React, { useState, memo } from 'react';
    
    function App() {
    
    const [count,setCount] = useState(0);
    
    return <div>
     <span>{count}</span>
     <button onClick={() => setCount(count + 1) }>+</button>
     <Foo />
    </div>
    }
    // 避免重新渲染
    const Foo = memo(function Foo () {
    console.log('Foo组件重新渲染')
    return <div>我是Foo组件</div>
    })
    
    
    export default App;
    
自定义Hook
  • ⾃定义 Hook 是标准的封装和共享逻辑的⽅式

  • ⾃定义 Hook 是⼀个函数, 其名称以 use 开头

  • ⾃定义 Hook 其实就是逻辑和内置 Hook 的组合.

    自定义hook需要安装axios库

import React, { useEffect, useState } from 'react';
import axios from 'axios'

// 自定义hook
function useGetPost () {
  const [post,setPost] = useState(0);
  useEffect(()=>{
    axios.get('http://janet.show:1337/posts/1')
    .then(response => setPost(response.data))
  }, [])
  return [post, setPost]
}
function App() {
  const [post, setPost] = useGetPost()
  return <div>
    <div>{post.title}</div>
    <div>{post.content}</div>
  </div>
}

export default App;
React路由Hooks

React-router-dom 路由提供的钩子函数

import React from 'react';
import { useHistory, useLocation, useRouteMatch, useParams} from 'react-router-dom'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkT8Ms1w-1613552571335)(images/image-20210215225523356.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值