React的使用

316 阅读4分钟

react和vue对比

相同点

  • MV*框架,
  • 虚拟DOM(但diff算法不同),
  • 专注于视图层

不同点

  • API来说:vue提供了指令,以及拥有双向数据绑定等概念,react没有提供指令,但是用于受控组件和非受控组件的概念
  • 性能优化来说:vue框架自动提供性能优化,手工优化(memo、useMemo、useCallback)
  • 从文件上来说:vue是一种SFC(single file component)的方式,react是以jsx这种方式

useState的使用

  • 更新普通类型的数据
setState(123)
  • 更新对象、对象的值

对象、数组引用类型值只要引用地址没有发生变化,状态就不会发生变化,页面也不会触发页面更新

// 更新数组
const [state,setState] = useState(['tom','lily'])
setState([...state,'anmy'])
// 更新对象
const [state,setState] = useState({name:'tom',age:18})
setState({...state,age:19})
  • useState可以接收一个函数 这样可以减少计算,如果是useState(1+1),那么首次加载的时候1+1会被重新计算
let [n, setN] = useState(()=>1+1);
  • setN也可以是个函数(推荐使用)
setN(n=>n+1);

如果不写函数会出现以下问题:当多次setN的时候只会执行最后一次,所以只加1了

let add = () => {
   //只会加1,如果n不传递那么也会执行一次setN(()=>n+1)
    setN(n+1);
    setN(n+1)
 };

如果想要批量更新可以使用函数的方式,函数必须使用要传递参数

setCount((count)=>count+1)
setCount((count)=>count+1)
setCount((count)=>count+1)

react17和react18对比

  1. 在 React 18 之前,React 事件处理程序期间批量更新。默认情况下,React 中不会批处理 Promise、setTimeout等的更新,React 18 所有的都会批量更新,这一定程度上减少了性能的损耗。 原文链接

react

useReducer的使用

是用来代替useState 1.创建初始值

let initVal = {
 n: 1,
};

2.创建所有操作reducer

let reducer = (state, action) => {
 if (action.type === "add") {
   return { n: state.n + action.params };
 } else if (action.type === "mul") {
   return { n: (state.n *= action.params) }
 }else{
   throw new Error('没有对应的类型')
 }
};

3.创建读和写API

let [state,dispatch] = useReducer(reducer,initVal)

4.调用写API

onClick={()=>dispatch({type:'add',params:2})}

完整代码如下:

import { useReducer } from "react";
let initVal = {
  n: 1,
};
let reducer = (state, action) => {
  if (action.type === "add") {
    return { n: state.n + action.params };
  } else if (action.type === "mul") {
    return { n: (state.n *= 2) }
  }else{
    throw new Error('没有对应的类型')
  }
};
function App() {
  let [state,dispatch] = useReducer(reducer,initVal)
  return (
    <div>
      state.n的值{state.n}
      <button onClick={()=>dispatch({type:'add',params:2})}>+1</button>
    </div>
  );
}

useContext的使用

useContext个人理解是一个组件间快速传值的过程。如下代码是通过props父子传递参数,子组件再去更改父组件的状态。

//父组件
function Father() {
  let [state,setState] = useState(0)
  return (
    <div>
      这是父组件{state}
      <Son value={{state,setState}}/>
    </div>
  );
}

//子组件
<button onClick={()=>{
        props.value.setState(props.value.state+1)
}}>+1</button>

但是当父子组件层级非常多的时候props的方式显得非常臃肿,这时useContext就非常好用了。 1.创建上下文

const Context = React.createContext(null);
  1. 指定作用域
let [state,dispatch] = useState(0)
  return (
    <context.Provider value={{ state,dispatch }}>
      <Father />
    </context.Provider>
  );

3.接收值(作用域范围都可以接收)

let { state, dispatch } = useContext(context);
onClick={()=>dispatch(state+10);

useEffect和useLayoutEffect的使用

useEffect(()=>{},[]) //第一次render时更新,相当于componentDidMount
useEffect(()=>{},[n])  //n的值发生变化时更新,包括第一次render的时候,如果第二个参数没有,
                       //所有数据都变化时更新
useEffect(()=>()=>{})   //传递一个函数,组件卸载之前更新相当于componentWillUnMount

useLayoutEffect要早于useEffect调用

优先使用useEffect,useLayoutEffect中加载的1000在页面还未渲染到页面时更新里面的值,不会产生闪烁的效果,但是会延迟页面的显示 useEffect.png

useMemo的使用

用法

// calculateValue是一个函数用来计算更新的值(首次、依赖发生变化会调用该函数)
// dependencies是当依赖更新时会重新调用calculateValue
const cachedValue = useMemo(calculateValue, dependencies)
// 例子 
const sum2 = useMemo(function(){
    console.log('sum2被调用了')
    const arr = Array.from({ length: 100 }).fill(1)
    const data  = arr.reduce((pre, next) => pre + next, 0)
    return data
},[])

使用场景

  • 跳过计算,避免多次计算,可以根据依赖来进行更新计算

  • 避免组件不必要的更新

    如下,当点击按钮时,会触发点击事件handleState,会更新state的值,从而使得App组件被更新,由于组件Son嵌套在App组件中,也会引发更新,但是Son组件更新时不必要的更新

import { useState, useMemo } from 'react'
function App() {
  const [state, setState] = useState("name")
  const handleState = () => {
    //处理状态
    setState('我更新了状态')
  }
  return (
    <>
      <p>
        {state}
      </p>
      <Son />
      <button onClick={handleState}>
        我是按钮
      </button>
    </>
  )
}
function Son(){
  console.log('我是Son组件,我被更新了')
  return (<>
  </>)
}
export default App

这种情况下可以使用memo来使得组件Son引发不必要的更新,在组件Son中使用memo来包裹,

import { useState, useMemo, memo } from 'react'
import './App.css'

function App() {
  const [state, setState] = useState("name")
  const handleState = () => {
    //处理状态
    setState('我更新了状态')
  }
  return (
    <>
      <p>
        {state}
      </p>
      <Son />
      <button onClick={handleState}>
        我是按钮
      </button>
    </>
  )
}
const Son = memo(function (){
  console.log('我是Son组件,我被更新了')
  return (<>

  </>)
})

export default App

当父组件的状态更新时,并且子组件中的props是一个对象时,因为父组件中的状态发生更新,并且因为props地址指针发生变化,导致子组件发生更新,但是此时状态发生更新是不必要的

import { useState, useMemo, memo } from 'react'
import './App.css'

function App() {
  const [state, setState] = useState("name")
  const handleState = () => {
    //处理状态
    setState('我更新了状态')
  }
  const handleSon = () =>{

  }
  return (
    <>
      <p>
        {state}
      </p>
      <Son handleSon={handleSon}/>
      <button onClick={handleState}>
        我是按钮
      </button>
    </>
  )
}
const Son = memo(function ({handleSon}){
  console.log('我是Son组件,我被更新了')
  return (<>
      <button onClick={handleSon}>

      </button>
  </>)
})

export default App

使用useMemo进行优化

import { useState, useMemo, memo } from 'react'
import './App.css'
function App() {
  const [state, setState] = useState("name")
  const handleState = () => {
    //处理状态
    setState('我更新了状态')
  }
  const handleSon = useMemo(() =>{
    // return 要返回的值,这里是个函数
    return  () =>{
    }
  },[])

  return (
    <>
      <p>
        {state}
      </p>
      <Son handleSon={handleSon}/>
      <button onClick={handleState}>
        我是按钮
      </button>
    </>
  )
}
const Son = memo(function ({handleSon}){
  console.log('我是Son组件,我被更新了')
  return (<>
      <button onClick={handleSon}>
      </button>
  </>)
})

export default App

useRef

useRef用来存储同一个变量