我是初学者,恐怕我完全糊涂了。
做一个记忆游戏练习,我想从(比如)40个文件夹中随机选择一个3x3的图像网格,当单击一个图像时,随机生成一组9个新的图像 clickCount
在游戏状态下(目标是点击尽可能多的未点击的图片)。也许问题在于我的thinkpad速度慢,但返回带有URL的对象数组的函数耗时太长,以致应用程序可能崩溃(随机数组未就绪)或随机跳过加载时的图像函数调用(希望在添加记分板逻辑之前解决此问题,如下所示)。
我只是从react开始,所以我一直在梳理 suspense
, memo
、延迟加载、承诺/异步等。但在我学习的早期阶段,我很难充分理解哪一个适合这种情况。
imageloader.js
// Import all images (Webpack)
const importAll = (r) => {
let images = [];
r.keys().forEach((item, i) => {
images.push({
...r(item),
id: `img${i}`,
clickCount: 0,
});
});
return images;
};
const imageExport = importAll(require.context("./images", false, /\.jpg$/));
export { imageExport };
game.js
import React, { useState, useEffect, useCallback } from "react";
import ImageElement from "./ImageElement";
import { imageExport } from "../imageLoader";
import "../styles/Game.css";
// SET GRID SIZE (no. of tiles per length of square)
const gridSize = 3;
const Game = () => {
const [gameState, setGameState] = useState(imageExport);
const [isLoaded, setIsLoaded] = useState(0);
const [tileSet, setTileSet] = useState(null);
const gridCount = gridSize**2;
// function to return random tile array
const randomiseTiles = useCallback(
(gridCount) => {
const imgQuantity = Object.keys(gameState).length;
const getRandomIndex = () => Math.floor(Math.random() * imgQuantity);
let imgIndexes = [];
for (let i = 0; i < gridCount; i++) {
const newRandomIndex = getRandomIndex();
if (imgIndexes.some((index) => index === newRandomIndex)) {
// is duplicate, try again
i--;
} else {
imgIndexes.push(newRandomIndex);
}
}
// FIX: successive high IDs crash the app as the array isn't ready in time
const imgSet = imgIndexes.map((id) => gameState[id]);
if (!imgSet.some((img) => img.clickCount !== 0)) {
// add logic later to guarantee at least one img is always unclicked
}
return imgSet;
},
[gameState]
);
// setTileSet after initial render to keep useState immutable
useEffect(() => {
if (!tileSet) {
setTileSet(randomiseTiles(gridCount));
}
}, []);
// report loading
const reportLoaded = () => {
setIsLoaded((prevIsLoaded) => {
if (prevIsLoaded < gridCount) {
return prevIsLoaded + 1;
};
// FIX: Is there a better way to reset isLoaded?
return 1;
});
};
// generate new tile set on image click
useEffect(() => {
setTileSet(randomiseTiles(gridCount));
}, [gameState, randomiseTiles, gridCount]);
// update game state on click
const updateGameState = (id) => {
const index = Number(id);
setGameState((prevGameState) => {
const newGameState = [...prevGameState];
newGameState[index] = {
...prevGameState[index],
clickCount: prevGameState[index].clickCount + 1,
};
return newGameState;
});
};
const gameStyle = isLoaded === gridCount ? {
display: "grid",
gridTemplateColumns: `repeat(${gridSize}, 1fr)`,
gridTemplateRows: `repeat(${gridSize}, 1fr)`,
} : {
display: "none"
};
return !tileSet ? null : (
<>
{isLoaded < gridCount && <div>Replace with loader animation etc.</div>}
<div id="game" style={gameStyle}>
{/* FIX: Sometimes renders before tileSet is ready /*}
{tileSet.map((img) => {
return (
<ImageElement
key={img.id}
src={img.default}
imgId={img.id}
reportLoaded={reportLoaded}
reportClick={updateGameState}
/>
);
})}
</div>
</>
);
};
export default Game;
imageelement.js
import React from "react";
// pure component
export default const ImageElement = ({ src, reportLoaded, reportClick, imgId }) => {
return (
<img
key={`image-${imgId}`}
src={src}
alt="image-alt-text"
{/* I randomly get between 5-9 triggers of reportLoaded on each click
even when all images load on the screen correctly
*/}
onLoad={reportLoaded}
onClick={() => reportClick(imgId)};
/>
);
};
问我任何你想问的问题如果我不清楚,我只是完全停留在这一点上,并将感谢一些意见(对概述的问题或任何其他我做了错事)。
非常感谢。
1条答案
按热度按时间9cbw7uwe1#
你正在做一些效率低下的事情。
array.some()
每次查看数组1个元素,直到找到匹配项或到达数组末尾。做一次很好,但你正在做gridCount
时间开始累积。而不是array.some()
,您可以创建一个对象来跟踪使用了哪些索引:另一个低效的做法是,您选择的随机索引比实际需要的要多,因为您允许它选择已经使用过的索引,然后将它们丢弃。以下是如何只选择所需的索引数:
上面的代码就是选择索引所需的全部代码。看看表演会发生什么。