https://tech.nextroll.com/ここの自動テキスト入力の箇所を実装してみたときのメモです。
Promiseだらけになってますが、もっと簡単にできる?
カーソルは|をアニメーションで点滅させて表現しています。
ソース(抜粋)
import React, { useState, useEffect } from "react";
import "./home/Home.css";
const MAIN_TEXT = "Join NextRoll as we build";
const SUB_TEXT1 = "modern web UIs";
const SUB_TEXT2 = "scalable data pipelines";
const SUB_TEXT3 = "open source software";
const SUB_TEXT4 = "real-time bidding";
const array_text = [SUB_TEXT1, SUB_TEXT2, SUB_TEXT3, SUB_TEXT4];
export const Test: React.FC = () => {
const [subText, setSubText] = useState([""]);
const addChar = (array: string[], val: string): string[] => {
array.push(val);
return [...array];
};
const delChar = (array: string[]): string[] => {
array.pop();
return [...array];
};
//SUB_TEXT1~SUB_TEXT4を受け取り、文字入力したり削除したり
const autoTypeText = (text: string) =>
new Promise((resolve, reject) => {
const array = Array.from(text);
Promise.resolve()
.then(() => {
//入力
return Promise.all(
array.map((val: string, index) => {
return new Promise((resolve1, reject) => {
setTimeout(() => {
setSubText((prev) => addChar(prev, val));
resolve1(true);
}, 50 * index);
});
})
);
})
.then(() => {
//少し待つ
return new Promise((resolve2) => {
setTimeout(() => {
resolve2(true);
}, 1000);
});
})
.then((values) => {
//削除
return Promise.all(
Array.from({ length: text.length }).map((val, index) => {
return new Promise((resolve3, reject) => {
setTimeout(() => {
setSubText((prev) => delChar(prev));
resolve3(true);
}, 50 * index);
});
})
);
})
.then(() => {
//少し待って終わる
return new Promise(() => {
setTimeout(() => {
resolve(true);
}, 500);
});
});
});
//無限ループ
const infiniteTextLoop = () => {
(async () => {
for (let i = 0; ; i++) {
await autoTypeText(array_text[i]);
if (i === array_text.length - 1) i = -1;
}
})();
};
useEffect(() => {
infiniteTextLoop();
}, []);
return (
<div style={{ margin: "20px", fontSize: "20px" }}>
<span style={{ marginRight: "8px" }}>{MAIN_TEXT}</span>
<span>{subText}</span>
<span className="CursolSpan">|</span>
</div>
);
};
css(抜粋)
.CursolSpan {
color: black;
animation-duration: 0.7s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: infinite;
animation-direction: normal;
animation-fill-mode: none;
animation-play-state: running;
animation-name: blink;
}
@keyframes blink {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
参考
Promise直列の無限ループについて
https://zenn.dev/wintyo/articles/2973f15a265581