react hooks的学习记录

文章来源:https://www.bilibili.com/video/BV153411n7B5/?p=5&spm_id_from=333.880.my_history.page.click

1.为什么要用hooks ,单纯的使用class组件不行吗?

react是用于构建用户界面的JavaScript库,使用class组件有点大材小用,组件中很少用到class的继承,组件之间很少进行访问,但是使用函数式组件,他能更好的胜任根据状态来渲染UI的工作,hooks内部拥有了维护状态的能力,且hooks带来了逻辑复用的能力.

2.react模型的本质

react模型本质就是model->views的一个过程,给他数据,他将为你展示ui,即state+props=组件

3.hooks是什么

hooks是函数,是一个提供了状态和生命周期等特性的函数

4.在什么时候使用setState使用回调函数作为参数

1.初始状态需要经过一些计算,localStorage中拿值

2.状态需要迭代累加,setXxx((上一次的值)=>{return 新的值}),即多次调用setXxxx,页面显示的是多次调用setXxxx后的新值,而不是最后一个setXxx覆盖得到的新值.

function addClick(){
    setCount(count + 1)
    setCount(count + 1)
    setCount(count + 1) //最后一次的值覆盖上面的值
}

function addClick(){
    setCount((num)=>{
        return num + 1
    })
    setCount((num)=>{
        return num + 1
    })
    setCount((num)=>{   //最后一次的调用,是基于上次是调用结束后的值
        return num + 1
    })
}
//这两种调用方式在页面展示的内容是不一样的
5.useState更新视图的过程

1.setState的每次调用,都会使函数式组件里面的代码重新走一遍

2.useState只会在组件初次渲染的时候使用初始值,之后都会使用更新后的值

3.一个函数式组件中的state是共享的,多次渲染会相互影响

6.副作用,useEffect

函数式组件除了渲染UI之外的操作都算是副作用操作

1.主要作用:函数式组件里面的return 的jsx ; 定义的state等

2.副作用:请求,修改dom,定时器的定义和清除,localStarage等

推荐将副作用的代码写在useEffect里面

7.useEffect的执行时机

1.页面挂载的时候执行一次(componentDidMount)

2.页面更新的时候触发,可能触发多次(componentDidUpdate)

3.在useEffect中发送ajax请求的小细节

//1.错误写法
useEffect(async ()=>{
    const res = await fetchGetApi(data)
    console.log(res)
},[])

//2.正确写法
useEffect(()=>{
    const getData = async ()=>{
        const res = await fetchGetApi(data)
        console.log(res)  
    }
    getData()
},[])

//useEffect要求他的回调函数是同步的,加上了async会导致该回调函数成为异步函数
8.useEffect的第二个参数

1.没有参数时:

useEffect(()=>{
    console.log("useEffect")
    //1.页面初次挂载会执行,
    //2.页面更新可能会多次执行
})

2.参数为[]

useEffect(()=>{
    console.log("useEffect")
    //1.页面初次挂载时执行,类似vue的created和mounted,可以用来发送请求
},[])

3.参数为数组,里面有值

const [n,setN] = useState(1)
const [info] = useState({name:"ls",age:12})

useEffect(()=>{
    console.log("useEffect")
    //1.页面初次挂载时执行,
    //2.所依赖的项发生变化也会执行
},[n,info])
9.useEffect副作用函数的返回值,来清理副作用

1.useEffect副作用函数的返回值可省略,也可以返回一个清理函数,清理函数会在组件卸载时触发,也会在下一次副作用函数执行之前触发

useEffect(()=>{
    console.log("副作用函数")
    return '清理函数'
},[])

useEffect(()=>{
    console.log("副作用函数")
    return ()=>{
        console.log("清理函数")
    }
})

2.应用场景,例如移除window监听的事件

useEffect(()=>{
    const fn = (e)=>{
        console.log(e.pageX,e.pageY)
    }
    window.addEventListener('mousemove',fn)
	return ()=>{
        window.removeEventListener('mousemove',fn)
    }
})

3.应用于类组件的componentWillUnmounted生命周期,即组件卸载时需要做的逻辑操作

useEffect(()=>{
    return ()=>{
        console.log("组件卸载时要做的操作")
    }
},[])
10.自定义hooks,逻辑复用

自定义hooks提取公共逻辑,并且封装成一个函数,该函数以"use"开头,根据不用的参数可以有不同的返回值.自定义hooks只能用在函数式组件中或者其他自定义hooks中

import { useEffect, useRef, useState } from "react"

function CountDown() {
  const [count, setCount] = useState(3) 
  const timeId = useRef(null)
  useEffect(() => {  //页面加载时执行的动作
    setCount(3)
    // 1.开始倒计时
    timeId.current = setInterval(() => {
      setCount(count=>count-1)
    }, 1000);
  }, [])
  //倒计时结束需要清空定时器
  useEffect(() => { 
    if (count === 0) { 
      console.log('倒计时结束执行的动作');
      clearInterval(timeId.current)
    }
  }, [count])
  
  //组件卸载时需要清空定时器
  useEffect(() => {
    return () => { 
      clearInterval(timeId.current)
    }
  },[])
  return <div>1</div>
}
export default CountDown

提取成自定义hook后的代码

/**
 * 
 * @param {*} initCount 初始倒计时的值,有用户传递,默认10s
 * @param {*} callback 倒计时结束后需要执行的动作
 * @returns 倒计时的数字和什么时候开始倒计时的函数
 */
export function useCountDown(initCount = 10, callback = () => { }) { 

  const [count,setCount] = useState(initCount)
  const timeId = useRef(null)
  
  const start = () => { 
    // 1.开始倒计时
    setCount(initCount)
    timeId.current = setInterval(() => {
      setCount(count=>count-1)
    }, 1000);
  }

  useEffect(() => { 
    if (count===0) {
      clearInterval(timeId.current)
    }
  }, [count])
  
  useEffect(() => { 
    return () => { 
      clearInterval(timeId.current)
    }
  },[])

  return {
    //需要将倒计时的数字返回回去
    count,
    //需要将什么时候开始执行倒计时返回
    start
  }
}
11.useRef

1.操作dom,获取组件

const inputRef = useRef(null)
const cusComp = useRef(null)
<input ref={inputRef}/>	
<CusComp ref={cusComp}/>
inputRef.current //就是获取到的dom或者组件

2.在多次渲染之间共享数据

//错误示例,无法清除定时器
function CusComp(){
    let timeId = null
    const [count,setCount] = useState(0)
    useEffect(()=>{
        timeId = setInterval(()=>{
            setCount(count=>count+1)
        },1000)
    },[])
    const cancle = ()=>{
        clearInterval(timeId)
    }
    
    return (<div>
            {count}
            <button onClick={cancle}></button>
            <div/>)
}


//使用useRef实现多次渲染的数据共享
import {useState,useEffect,useRef } from 'react'

function CusComp(){
  const [count, setCount] = useState(0)
  const timeId = useRef(null)
  useEffect(()=>{
      timeId.current = setInterval(()=>{
          setCount(count=>count+1)
      }, 1000)
    
  },[])
  const cancle = () => {
      clearInterval(timeId.current)
  }
  
  return <div>
          {count}
            <button onClick={cancle}>清除</button>
          </div>
}
export default CusComp
12.useContext - 全局状态

使用步骤:

//1.第一步 使用Context.provider包裹住根组件
import { createContext } from "react"
export const Context = createContext()

function App(){
	return <Context.Provider value={需要传递的值}>
		<div>根组件</div>
	</Context.Provider>
}	

//2.在其他组件中接收
import { useContext } from "react"
import { Context } from "根组件"
function Son(){
	const res = useContext(Context) //res 就是接收到的数据
	return <div>son</div>
}
13.redux:javaScript应用的状态容器,提供可预测的状态管理

1.redex的核心概念:store ,action , reducer

​ action : 一个js对象,包含两个属性:

​ type:标识属性,值是字符串.多个type用action分开

​ payload:数据属性,可选.表示本次动作携带的数据

​ action只是描述了有事情发生这一事实,并没有描述应用如何更新state

​ reducer: 一个函数,可以修改状态

const reduer = (preState, action) = {}

​ store:仓库,核心,整合action和reducer

​ 1.一个应用只有一个store

​ 2.获取状态: store.getState()

​ 3.创建store时,接收reducer作为参数:

const store = createStore(reducer)

​ 4.发生状态更新时:需要分发action : store.dispatch(action)

2.订阅及取消状态变化

​ 1.订阅状态变化:

const unSubscribe = store.subscribe(()=>{})   //  状态发生变化需要执行的逻辑

​ 2.取消订阅 : unSubscribe()

3.先订阅,后执行action 会触发订阅的回掉函数

4.示例代码

import { createStore } from "redex"
const initState = {
	count : 0
}
const action = { type:'add', payload:1}

const reducer = (prestate = initState,action) = {
    switch (action.type) {
    	case 'add':
    		prestate.count += 1
			return prestate
    default:
    	return prestate
    }
}

const store = createStore(reducer)
const unSubscribe = store.subscribe(()=>{})
store.dispatch(action)
14.react-redux 工具优化代码

1.引入Provider 将根组件App 包裹

import { Provider } from "react-redux"
import store from './store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>
  ,
  document.querySelector('#root')
)

2.初始化store.js文件

import { legacy_createStore as createStore } from "redux"
import reducer from "./reducers"

const store = createStore(reducer)

export default store

3.创建reducer.js文件,拆分模块

import { combineReducers } from "redux"
import userInfo from "./userInfo"
import role from "./role"


const rootReducer = combineReducers({
  userInfo,
  role
})

export default rootReducer

4.根据业务,分不同的reducer模块

const userInfo = {
  userName: '张三',
  age:12
}

const reducer = (preState = userInfo, action) => { 
  switch (action.type) {
    case 'userInfo/changeName':
      return {...preState,userName:action.payload}
    default:
      return preState
  }
}
export default reducer
const role = 0

const reducer = (preState = role, action) => { 
  switch (action.type) {
    case 'role/changeRole':
      return action.payload
    default:
      return preState
  }
}
export default reducer
15.纯函数:相同的输入总是会得到想用的输出
16.react router

1.安装路由

npm i react-router-dom

2.引入路由

import { HashRouter, BrowserRouter, Link, NavLink, Route, Switch } from "react-router-dom"

3.编写路由规则

//hash模式的路由
<HashRouter>
    <Link to='/home'>home</Link>
    <Route path='/home' component={Home}></Route>
</HashRouter>

//history模式
//hash模式的路由
<BrowserRouter>
    <NavLink to='/home' exact>home</NavLink>
    <Route path='/home' component={Home}></Route>
</BrowserRouter>

link 和navLink的跳转基本一样,NavLink有一个activeClassName来指定高亮样式,默认active

NavLink还能exact精准匹配,默认模糊匹配

4.Switch匹配到就不会继续往下匹配了,404页面放下最下面

<BrowserRouter>
    <NavLink to='/home' exact>home</NavLink>
    
    <Switch>
    	<Route path='/home' component={Home}></Route>
    	<Route path='/home/detail' component={Home}></Route>
    	<Route path='/404' component={Page404}></Route>
    </Switch>	
</BrowserRouter>

exact>home


link 和navLink的跳转基本一样,NavLink有一个activeClassName来指定高亮样式,默认active

NavLink还能exact精准匹配,默认模糊匹配

4.Switch匹配到就不会继续往下匹配了,404页面放下最下面

home
<Switch>
	<Route path='/home' component={Home}></Route>
	<Route path='/home/detail' component={Home}></Route>
	<Route path='/404' component={Page404}></Route>
</Switch>	
```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值