React loop calls useState synchronization processing scheme

Table of contents:

  1. scene introduction
  2. Circularly call useState synchronous processing scheme (add data)
    1. Change the callback function useState(data) to: useState(data => process data)
    2. Use variables outside the function
  3. Call usesate in a loop, and then add the interface to the original data scheme (add data + asynchronous interface)
    1. SetArr can be transformed into a function
    2. Encapsulate the callback function using useState
    3. Use useEffect to monitor changes

Recommended reading: React loops through the useState array asynchronously calling the interface to add parameters and modify the original array processing scheme: https://blog.csdn.net/weixin_44461275/article/details/121428336

Scene introduction:

After the map array is processed (filtering, etc.), it is called to the hooks exception. For example: add a product package, add it to the useState array after the loop call check. After the personnel array is processed, call the useState array and so on...

When using useState(), first understand the rules of Hook

  1. Hooks are called only at the top level: useState() cannot be called in loops, conditions, nested functions, etc. In multiple useState() calls, the order of calls must be the same between renders.

  2. Hooks are only called from React functions: useState() must be called inside function components or custom hooks.

So: hooks cannot be called inside a loop

.

Cycle call useState synchronous processing scheme:

  1. The callback function useState(data) is changed to: useState(data => process data)
  2. Use variables outside the function

Transformation of the former:

import React, {
    
     useState } from 'react';

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    age: parseInt(Math.random() * 1e2)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useState([]);
  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.age}`}> {
    
     item.name }{
    
     item.age }</div>)
      }
    </div>
  )
  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      setArr([...arr, obj()])
    }
  }
}

export default Home;

Result: Only one is added per click, not 5. Note that useState is asynchronous, and the latest data after the previous operation cannot be obtained
insert image description here

After transformation:

1. Change the callback function useState(data) to: useState(data => process data)

import React, {
    
     useState } from 'react';

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    age: parseInt(Math.random() * 1e2)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useState([]);
  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.age}`}> {
    
     item.name }{
    
     item.age }</div>)
      }
    </div>
  )
  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      // setArr([...arr, obj()]) //原来
      setArr(i => [...i, obj()]) //现在。 i是形参,当前为arr变量,可为x、y、a等
    }
  }
}

export default Home;

2. Replace the place declared using useState() with a global variable (outside the function component)

import React, {
    
     useState } from 'react';

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    age: parseInt(Math.random() * 1e2)
  }
}

let arr = [];
const Home = () => {
    
    
  const [other, setOther] = useState(0); //触发 render刷新 非必须可用项目其他方式

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.age}`}> {
    
     item.name }{
    
     item.age }</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      arr = [...arr, obj()];
      setOther(Math.random()); //核心 只要能触发 render再次刷新的其他方式都行 否则arr数据已更新,dom也不刷新
    }
  }
}

export default Home;

Result:
insert image description here
normal~~

Note: setOther(Math.random()); is just to refresh the render, as long as it can trigger the refresh, it can be replaced by other! ! ! render does not refresh, useEffect cannot monitor changes


For some projects, each data is required, and then added after querying the query interface

The loop usesate internal call interface is added to the original data scheme

  1. Can change setArr to function
  2. Encapsulate the callback function using useState
  3. Borrow useEffect to monitor changes

1. SetArr can be transformed into a function:

import React, {
    
     useState } from 'react';

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    id: parseInt(Math.random() * 1e4)
  }
}

let arr = [];
const Home = () => {
    
    
  // let [arr] =  useState([]); 和 外部let arr = []; 二选一
  const [other, setOther] = useState(0); //触发 render刷新 非必须可用项目其他方式

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.id}`}> {
    
     item.name }{
    
     item.id } {
    
     item?.addKey || ''}</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      let getObj = obj();
      arr = [...arr, getObj];
      setArr(getObj);
      setOther(Math.random()); //核心 只要能触发 render再次刷新的其他方式都行 否则arr数据已更新,dom也不刷新
    }
  }
  
  //原始:let [arr, setArr] =  useState([]); 中setArr异步请求接口 追加参数
  function setArr(ops){
    
    
    let setTime = parseInt(Math.random() * 1e4);
    // 模拟异步接口请求,且接口返回时间不稳定
    setTimeout(() => {
    
    
      arr.map((ii, idx) => {
    
    
        if(ii.id == ops.id){
    
    
          ii.addKey = '追加的key用时:' + setTime;
          arr[idx] = ii;
        }
      })
      setOther(Math.random()); //核心 只要能触发 render再次刷新的其他方式都行 否则arr数据已更新,dom也不刷新
    }, setTime)
  }
}

export default Home;

2. Encapsulate the callback function using useState:

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

function useCallbackState (od) {
    
    
  const cbRef = useRef();
  const [data, setData] = useState(od);

  useEffect(() => {
    
    
      cbRef.current && cbRef.current(data);
  }, [data]);

  return [data, function (d, callback) {
    
    
      cbRef.current = callback;
      setData(d);
  }];
}

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    id: parseInt(Math.random() * 1e4)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useCallbackState([]);

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.id}`}> {
    
     item.name }{
    
     item.id } {
    
     item?.addKey || ''}</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      setArr(i => [...i, obj()], (data) => {
    
    
        // 5次循环只执行一次,且是最后一次
        addKeyFun(data);
      })
    }
  }
  
  // 追加参数
  function addKeyFun(data){
    
    
    data.map((ii, idx) => {
    
    
      let setTime = parseInt(Math.random() * 1e4);

      // 模拟异步接口请求,且接口返回时间不稳定
      setTimeout(() => {
    
    
        setArr(i => {
    
    
          i[idx].addKey = '追加的key用时:' + setTime;
          return [...i]
        });
      }, setTime)
    })
  }
}

export default Home;

3. Use useEffect to monitor changes
3.1: Use Promise.all() in es6 to process (complex tasks are also applicable)
3.2: Use the callback function callback in es5 to process (the logic is a bit convoluted, because the order needs to be fixed)
3.3: UseState callback function writing (Additional test processing is required when the amount of data is large)

.

3.1: Use Promise.all() in es6 to process

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

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    id: parseInt(Math.random() * 1e4)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useState([]);

  useEffect(() => {
    
    
    addKeyList()
  }, [arr.length])
  // 注意监听arr.length 而不是arr 否则死循环

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.id}`}> {
    
     item.name }{
    
     item.id } {
    
     item?.addKey || ''}</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      setArr(i => [...i, obj()]); //一定要使用函数方式
    }
  }
  
  // 循环添加处理
  function addKeyList(){
    
    
    // taskList是一个promise任务数组
    let taskList = arr.map(item => {
    
    
      return addKeyFun(item)
    })
    Promise.all(taskList).then(res => {
    
    
      setArr(res); //所有接口请求返回后才会一次性渲染
    })
  }
  
  // 追加参数
  function addKeyFun(item){
    
    
    return new Promise((resolve, reject) => {
    
    
      let setTime = parseInt(Math.random() * 1e4);
      // 模拟异步接口请求,且接口返回时间不稳定
      setTimeout(() => {
    
    
        item.addKey = '追加的key用时:' + setTime;
        resolve(item)
      }, setTime)
    })
  }
}

export default Home;

3.2: Use the callback function callback in es5 to process

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

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    id: parseInt(Math.random() * 1e4)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useState([]);

  useEffect(() => {
    
    
    addKeyList()
  }, [arr.length])
  // 注意监听arr.length 而不是arr 否则死循环

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.id}`}> {
    
     item.name }{
    
     item.id } {
    
     item?.addKey || ''}</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      setArr(i => [...i, obj()]); //一定要使用函数方式
    }
  }

  // 循环添加处理
  function addKeyList(){
    
    
    let httpNum = 0;
    let resArr = [...arr];
    arr.map((item, index) => {
    
    
      addKeyFun(item, index, (obj, idx) => {
    
    
        httpNum++; //每次接口请求记录次数+1,注意不管接口成功还是失败都要+1,注意接口error处理
        resArr[idx] = obj; //赋值新数据到数组
        if(httpNum == arr.length){
    
     //最后一次请求-统一设置到数组
          setArr(resArr);
        }
      })
    })
  }
  
  // 追加参数
  function addKeyFun(item, index, callback){
    
    
      let setTime = parseInt(Math.random() * 1e4);
      // 模拟异步接口请求,且接口返回时间不稳定
      setTimeout(() => {
    
    
        item.addKey = '追加的key用时:' + setTime;
        callback && callback(item, index);
      }, setTime)
  }
}

export default Home;

3.3: UseState callback function writing method (additional test processing is required when the amount of data is large)

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

// 随机对象 用于模拟区分
function obj() {
    
    
  return {
    
    
    name: `某某`,
    id: parseInt(Math.random() * 1e4)
  }
}

const Home = () => {
    
    
  const [arr, setArr] = useState([]);

  useEffect(() => {
    
    
    addKeyFun(arr)
  }, [arr.length])
  // 注意监听arr.length 而不是arr 否则死循环

  return (
    <div>
      <button onClick={
    
     addObj }>点击+5条数据</button>
      {
    
    
        arr.map(item => <div key={
    
    `arr${
      
      item.id}`}> {
    
     item.name }{
    
     item.id } {
    
     item?.addKey || ''}</div>)
      }
    </div>
  )

  // 点击+5条数据
  function addObj(){
    
    
    for (let i = 0; i < 5; i++) {
    
    
      setArr(i => [...i, obj()]); //一定要使用函数方式
    }
  }
  
  // 追加参数
  function addKeyFun(data){
    
    
    data.map((ii, idx) => {
    
    
      let setTime = parseInt(Math.random() * 1e4);

      // 模拟异步接口请求,且接口返回时间不稳定
      setTimeout(() => {
    
    
        setArr(i => {
    
    
          i[idx].addKey = '追加的key用时:' + setTime;
          return [...i]
        });
      }, setTime)
    })
  }
}

export default Home;

Result:
insert image description here
After all requests are completed:
insert image description here


Guess you like

Origin blog.csdn.net/weixin_44461275/article/details/121269054