useState的数组,遍历请求异步接口,追加参数后,更新设置原数组
方案01. 可改造 setArr为function
方案02. 封装使用useState的回调函数
方案03:【推荐】useEffect + es6中的Promise.all()处理(复杂任务也适用)
方案04:useEffect + es5中的回调函数callback处理(逻辑有点绕,因要固定排序)
方案05:useEffect + useState回调函数写法(数据量大的时候需要额外测试处理)
.
1.改造useState的更新方法setArr为回调函数:
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.封装使用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:useEffect + es6中的Promise.all()处理(复杂任务也适用)
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;
4:useEffect + es5中的回调函数callback处理(逻辑有点绕,因要固定排序)
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;
5:方案05:useEffect + useState回调函数写法(数据量大的时候需要额外测试处理)
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;
结果:
全部请求完毕后:
推荐活跃的同学加一下QQ群:152693086(大前端),欢迎加入。