使用 setTimeout 反应嵌套地图顺序渲染
React nested map sequential render with setTimeout
我的目标是遍历字符数组并在给定单词的每个字母处结束。我的代码当前同时显示所有这些元素,但我希望它们按顺序显示。这是我目前拥有的:
Current view
我要return以h结尾的数组(稍等片刻),e[=结尾的数组31=](稍等片刻),依此类推。我不知道如何将 arrayIndex 附加到嵌套映射。
DisplayName.js
import React, { useState, useEffect } from "react";
const DisplayName = ({ characters, first }) => {
const [charIndex, setCharIndex] = useState(0);
const [arrayIndex, setArrayIndex] = useState(0);
let arrayContainer = [];
first.map((letter, i) => {
arrayContainer.push([]);
arrayContainer[i].push(characters.concat(first[i]));
return arrayContainer;
});
// I can't figure out how to attach arrayIndex here. I am
// also not using j currently, but kept it for now in case I need
// a key for the return statements.
const fullList = arrayContainer.map((letterArr, j) => {
return letterArr.map(char => {
return (char[charIndex])
})
});
useEffect(() => {
let timer;
let secondTimer;
if (charIndex < characters.length) {
timer = setTimeout(() => {
setCharIndex(charIndex + 1)
}, 75)
}
if (arrayIndex < first.length - 1) {
secondTimer = setTimeout(() => {
setArrayIndex(arrayIndex + 1)
}, 75)
}
return () => {
clearTimeout(timer);
clearTimeout(secondTimer);
};
}, [charIndex, characters, arrayIndex, first]);
return (
<div>{fullList}</div>
)
};
export default DisplayName;
App.js
import React from 'react';
import DisplayName from './DisplayName';
import './App.css';
function App() {
const first = 'hello'.split('');
const funChars = [
'⏀', '⎷', '⌮', '⋙', '⊠', '⎳', '⍼',
'⍣', '╈', '╳', '☀', '★', '☍', 'ↂ','▅'];
return (
<div className="glow" style={{ minHeight: '100vh'}}>
<span style={{ letterSpacing: 12}}><DisplayName first={first} characters={funChars}/></span>
</div>
);
}
export default App;
我也尝试过 const [rendered, setRendered] = useState(false);
之类的东西但没有成功,我尝试将其附加到 j
键。
如果我理解你的问题,你想迭代 first
字符串直到索引并在迭代字符串时显示“滚动”有趣的字符。
直觉上我认为更容易想到将 first
字符串的前面切片到索引,然后附加有趣的字符。
iteration
index
text.substring(0, index)
result(s)
0
0
""
'⏀', '⎷', '⌮',...
1
1
"h"
'h⏀', 'h⎷', 'h⌮',...
2
2
"he"
'he⏀', 'he⎷', 'he⌮',...
3
3
"hel"
'hel⏀', 'hel⎷', 'hel⌮',...
4
4
"hell"
'hell⏀', 'hell⎷', 'hell⌮',...
5
5
"hello"
'hello'
棘手的问题是使用两个单独的 timers/intervals 来递增 first
字符串的索引并递增 fun characters 数组的索引。这是我想出的解决方案。
- 使用 React 引用来保存滚动有趣角色的间隔计时器引用。
- 单个
useEffect
挂钩开始“滚动”有趣的字符索引,按时间间隔递增。在 first
字符串字符数组递增时开始超时,如果仍有长度要迭代,则将另一个超时排队,否则 运行 清理函数以清除计时器和状态。
- 将
first
字符串切片到索引 arrayIndex
并有条件地附加一个“滚动”有趣的字符。
代码:
const DisplayName = ({ characters, first }) => {
const charTimerRef = useRef(null);
const [charIndex, setCharIndex] = useState(null);
const [arrayIndex, setArrayIndex] = useState(0);
useEffect(() => {
let timerId;
const cleanupTimerRef = () => {
setCharIndex(null);
clearInterval(charTimerRef.current);
charTimerRef.current = null;
};
if (!charTimerRef.current) {
setCharIndex(0);
charTimerRef.current = setInterval(() => {
setCharIndex((i) => i + 1);
}, 75);
}
if (arrayIndex < first.length) {
timerId = setTimeout(() => {
setArrayIndex((i) => i + 1);
}, 1000);
} else {
cleanupTimerRef();
}
return () => {
clearTimeout(timerId);
cleanupTimerRef();
};
}, [arrayIndex, first]);
const fullList =
first.substring(0, arrayIndex) +
(charIndex ? characters[charIndex % characters.length] : "");
return <div>{fullList}</div>;
};
演示
我的目标是遍历字符数组并在给定单词的每个字母处结束。我的代码当前同时显示所有这些元素,但我希望它们按顺序显示。这是我目前拥有的:
Current view
我要return以h结尾的数组(稍等片刻),e[=结尾的数组31=](稍等片刻),依此类推。我不知道如何将 arrayIndex 附加到嵌套映射。
DisplayName.js
import React, { useState, useEffect } from "react";
const DisplayName = ({ characters, first }) => {
const [charIndex, setCharIndex] = useState(0);
const [arrayIndex, setArrayIndex] = useState(0);
let arrayContainer = [];
first.map((letter, i) => {
arrayContainer.push([]);
arrayContainer[i].push(characters.concat(first[i]));
return arrayContainer;
});
// I can't figure out how to attach arrayIndex here. I am
// also not using j currently, but kept it for now in case I need
// a key for the return statements.
const fullList = arrayContainer.map((letterArr, j) => {
return letterArr.map(char => {
return (char[charIndex])
})
});
useEffect(() => {
let timer;
let secondTimer;
if (charIndex < characters.length) {
timer = setTimeout(() => {
setCharIndex(charIndex + 1)
}, 75)
}
if (arrayIndex < first.length - 1) {
secondTimer = setTimeout(() => {
setArrayIndex(arrayIndex + 1)
}, 75)
}
return () => {
clearTimeout(timer);
clearTimeout(secondTimer);
};
}, [charIndex, characters, arrayIndex, first]);
return (
<div>{fullList}</div>
)
};
export default DisplayName;
App.js
import React from 'react';
import DisplayName from './DisplayName';
import './App.css';
function App() {
const first = 'hello'.split('');
const funChars = [
'⏀', '⎷', '⌮', '⋙', '⊠', '⎳', '⍼',
'⍣', '╈', '╳', '☀', '★', '☍', 'ↂ','▅'];
return (
<div className="glow" style={{ minHeight: '100vh'}}>
<span style={{ letterSpacing: 12}}><DisplayName first={first} characters={funChars}/></span>
</div>
);
}
export default App;
我也尝试过 const [rendered, setRendered] = useState(false);
之类的东西但没有成功,我尝试将其附加到 j
键。
如果我理解你的问题,你想迭代 first
字符串直到索引并在迭代字符串时显示“滚动”有趣的字符。
直觉上我认为更容易想到将 first
字符串的前面切片到索引,然后附加有趣的字符。
iteration | index | text.substring(0, index) | result(s) |
---|---|---|---|
0 | 0 | "" | '⏀', '⎷', '⌮',... |
1 | 1 | "h" | 'h⏀', 'h⎷', 'h⌮',... |
2 | 2 | "he" | 'he⏀', 'he⎷', 'he⌮',... |
3 | 3 | "hel" | 'hel⏀', 'hel⎷', 'hel⌮',... |
4 | 4 | "hell" | 'hell⏀', 'hell⎷', 'hell⌮',... |
5 | 5 | "hello" | 'hello' |
棘手的问题是使用两个单独的 timers/intervals 来递增 first
字符串的索引并递增 fun characters 数组的索引。这是我想出的解决方案。
- 使用 React 引用来保存滚动有趣角色的间隔计时器引用。
- 单个
useEffect
挂钩开始“滚动”有趣的字符索引,按时间间隔递增。在first
字符串字符数组递增时开始超时,如果仍有长度要迭代,则将另一个超时排队,否则 运行 清理函数以清除计时器和状态。 - 将
first
字符串切片到索引arrayIndex
并有条件地附加一个“滚动”有趣的字符。
代码:
const DisplayName = ({ characters, first }) => {
const charTimerRef = useRef(null);
const [charIndex, setCharIndex] = useState(null);
const [arrayIndex, setArrayIndex] = useState(0);
useEffect(() => {
let timerId;
const cleanupTimerRef = () => {
setCharIndex(null);
clearInterval(charTimerRef.current);
charTimerRef.current = null;
};
if (!charTimerRef.current) {
setCharIndex(0);
charTimerRef.current = setInterval(() => {
setCharIndex((i) => i + 1);
}, 75);
}
if (arrayIndex < first.length) {
timerId = setTimeout(() => {
setArrayIndex((i) => i + 1);
}, 1000);
} else {
cleanupTimerRef();
}
return () => {
clearTimeout(timerId);
cleanupTimerRef();
};
}, [arrayIndex, first]);
const fullList =
first.substring(0, arrayIndex) +
(charIndex ? characters[charIndex % characters.length] : "");
return <div>{fullList}</div>;
};