React常见的一些坑

文章目录

  • 两个基础知识
    • 1. react的更新问题, react更新会重新执行react函数组件方法本身,并且子组件也会一起更新
    • 2. useCallback和useMemo滥用
    • useCallback和useMemo要解决什么
    • 3. react的state有个经典的闭包,导致拿不到最新数据的问题.
    • 常见于useEffect, useMemo, useCallback
    • 4. 副作用方案
    • 总结

两个基础知识

1. react的更新问题, react更新会重新执行react函数组件方法本身,并且子组件也会一起更新

在这里插入图片描述

2. useCallback和useMemo滥用

useCallback和useMemo要解决什么

React.memo包装组件
React.useCallback包裹传递子组件函数

对于传递给组件的对象是固定不变的,和数据没有关系的.
需要将固定变量放在函数外层

React.useMemo: 当你给子组件的对象是和组件数据有关的, 也就是做一个计算属性时候
, 采用useMemo

3. react的state有个经典的闭包,导致拿不到最新数据的问题.

常见于useEffect, useMemo, useCallback

在这里插入图片描述

在这里插入图片描述

4. 副作用方案

在这里插入图片描述

在这里插入图片描述

App.jsx

import React, { useState, useRef, useEffect } from 'react'
import Filter from './components/Filter';
import Pagers from './components/Pagers';

import './App.css'

// * 如果这个对象是固定不变的,和state数据无关系, 需要提到组件外侧
const obj = {
  a:'cccc'
}

// useRef, 副作用方案
// 如果有一个state数据, 需要传递给子组件时候
// 建议把state数据定义为ref
function App() {
  const [count, setCount] = useState(0)
  const [filterData, setFilterData] = useState('')
  const [pageData, sePageData] = useState('')

  // useRef: 
  // 当有一个变量, 当这个变量不想被外部获取, 不需要写依赖
  // 并且还想获取state最新值, 此时,需要将state变为ref
  // useRef定义的变量【不会造成视图更新】
  // const filterData = useRef('')
  // const setFilterData = React.useCallback((val)=>{
  //   filterData.current = val
  // }, [])

  // 准备一个请求接口的方法给筛选栏
  // 再次更新,就会重新执行, 等于又在内存中新建了一个getList方法
  // 第一次渲染->getList 创建 1001 第二次->1002
  //1.  * useCallback并不是有方法一定要包裹, 只有当这个方法给子组件的时候才有

  // const getList = React.useCallback((page)=>{
  //   console.log('=item=====');
  //   // console.log(item);
  //   // *2.  useCallback, useEffect, useMemo方法. 如果用到state数据
  //   // * 一定要把state数据写在第二个数组中, 否则拿不到新数据

  //   // 改为useRef方式,  搜索栏更新,不会造成page更新
  //   console.log(count, filterData, page);
  // }, [count, filterData])


  // 方法3: 使用useEffect监听子组件变化, 不将getList方法传递子组件
  useEffect(() => {
    console.log(count, filterData, pageData);
  }, [count, filterData, pageData])
  

  // * 3. React.useMemo: 当你给子组件的对象是和组件数据有关的, 也就是做一个计算属性时候
  return (
    <>
 
      <h1>Vite + React</h1>
      <div className="card">
        父组件本身:
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
      <div>
        筛选栏:
        <Filter
        //  config={obj}
         filterData={filterData}
         setFilterData={setFilterData}
        //  getList={getList}
         />
      </div>
      <div className="read-the-docs">
        <Pagers 
          sePageData={sePageData}
          //  getList={getList}
        />
      </div>
    </>
  )
}

export default App

Pagers.jsx

import React from "react";

function Pagers(props) {
  console.log("pager render");
  const { sePageData } = props;
  return (
    <div className="Pager">
      {[1, 2, 3, 4, 5].map((i) => {
        return (
          <div
            key={i}
            onClick={() => {
              sePageData(i);
            }}
          >
            {i}
          </div>
        );
      })}
    </div>
  );
}

export default React.memo(Pagers);

Filter.jsx

import React, { useState } from 'react'


function Filter(props) {
  console.log('Filter render---');

  const { setFilterData } = props
  const value = React.useRef('')
  return (
    <>
     <input onChange={
      (e)=>{
        value.current = e.target.value
      }
     } ></input>
     <button  onClick={()=> setFilterData(value.current)}>搜索</button>
    </>
  )
}

export default React.memo(Filter)

总结

小结一下:
React 函数式组件会在state/props/context/父组件重新渲染时,重新执行函数,
为避免不必要的性能消耗(函数重新定义,某些值重新计算等等),减少重新渲染(或者重新执行函数式组件),需要控制props + 配合react.memo
控制props :

  1. 用useCallback暂存函数(注意用到state时要用好第二个参数)、useMemo避免复杂运算重复执行
  2. 用Ref(非受控组件)获取不需要渲染,但又是最新的值
  3. 不变的值写在函数式组外,避免重复创建
  4. jsx里尽量不写字面量、匿名函数

// useRef:
// 当有一个变量, 当这个变量不想被外部获取, 不需要写依赖
// 并且还想获取state最新值, 此时,需要将state变为ref
// ** useRef定义的变量【不会造成视图更新】**
// const filterData = useRef(‘’)
// const setFilterData = React.useCallback((val)=>{
// filterData.current = val
// }, [])

// 注意:useRef定义的变量【不会造成视图更新】,而state变量会视图更新, 也会被添加到依赖项, 会影响子组件更新

  1. 使用方案3, 使用useEffect监听子组件变化, 不将getList方法传递子组件
    ,只用将修改父组件数据的方法传递到子组件. 在父组件通过副作用更新

  2. 技巧4, 当数据只在子组件中使用时候, 而不会在页面展示时,
    需定义为useRef变量,(在页面展示时定义为state变量).

定义在组件内部, 在点击确定时候, 将数据更新到父组件, 修改时用.current修改

在这里插入图片描述

上一篇:【杂谈】AIGC之Stable Diffusion:AI绘画的魔法


下一篇:React实战(一)初始化项目、配置router、redux、axios