React常见的一些坑

作者 : admin 本文共3262个字,预计阅读时间需要9分钟 发布时间: 2024-06-2 共2人阅读

文章目录

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

两个基础知识

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

React常见的一些坑插图

2. useCallback和useMemo滥用

useCallback和useMemo要解决什么

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

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

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

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

常见于useEffect, useMemo, useCallback

React常见的一些坑插图(1)

React常见的一些坑插图(2)

4. 副作用方案

React常见的一些坑插图(3)

React常见的一些坑插图(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修改

React常见的一些坑插图(5)

本站无任何商业行为
个人在线分享 » React常见的一些坑
E-->