我已经在React中创建了一个网格组件。我有一个名为'availableColors'的字符串数组,我在其中存储我想使用的css类名。
在'RandomColorGrid'组件中,我在'useState'中设置每个网格项目的初始颜色,从'availableColors'分配一个索引到每个项目。
网格中的每个项目调用'changeColors()' onClick。在该方法中,我重新分配了'colors'中每个'box'的值,并从'availableColors'中随机选择了一个新的索引。
这工作得很好,但感觉有点笨拙。有两件事我一直在努力改进,但却卡住了。
;当'changeColors()'函数被调用时,我想只使用每种颜色一次。目前,可以在多个网格项目上使用相同的颜色,我希望它们每次都是四种独特的颜色。
第二;我不希望一件商品的颜色连续两次相同。因此,对于任何给定的项目,我将行从可能的随机选择中排除该项目的当前颜色。
我一直在努力实现这一点,通过采取当前颜色的颜色索引,并形成一个新的颜色数组,从每个项目随机选择,然后另一个数组尝试和跟踪已经使用的颜色,以避免重复,但在这样做已经进入一个真正的混乱。这让我相信我的设计可能从一开始就很糟糕。
我该如何改进?
import React, { useState } from "react";
const availableColors = ["red", "green", "blue", "yellow"];
const changeColors = (colors, setColors) => {
colors.box1 = availableColors[randomNumber(colors.box1)];
colors.box2 = availableColors[randomNumber(colors.box2)];
colors.box3 = availableColors[randomNumber(colors.box3)];
colors.box4 = availableColors[randomNumber(colors.box4)];
setColors({ ...colors });
};
const randomNumber = (currentColour) => {
let indices = [0, 1, 2, 3];
indices.splice(availableColors.indexOf(currentColour), 1);
return indices[Math.floor(Math.random() * indices.length)];
};
export const RandomColorGrid = () => {
let [colors, setColors] = useState({
box1: availableColors[0],
box2: availableColors[1],
box3: availableColors[2],
box4: availableColors[3],
});
return (
<div className="grid">
<div
className={`${colors.box1}`}
onClick={() => changeColors(colors, setColors)}
/>
<div
className={`${colors.box2}`}
onClick={() => changeColors(colors, setColors)}
/>
<div
className={`${colors.box3}`}
onClick={() => changeColors(colors, setColors)}
/>
<div
className={`${colors.box4}`}
onClick={() => changeColors(colors, setColors)}
/>
</div>
);
};
你的问题来自于不尊重对象的不变性。你改变了一个对象,并依赖于该对象在下一行(在changeColors中)不改变
解决方案是复制可用颜色的新数组,并使用.filter来确保我们不会重复相同的颜色两次,通过替换新的currentlyAvailableColors数组来只包含可以使用的颜色
const changeColors = (colors, setCurrentColours) => {
const nextColors = {};
let currentlyAvailableColors = [...availableColors];
nextColors.box1 = getRandomOption(colors.box1, currentlyAvailableColors)
currentlyAvailableColors = currentlyAvailableColors.filter(col => col !== nextColors.box1);
nextColors.box2 = getRandomOption(colors.box2, currentlyAvailableColors)
currentlyAvailableColors = currentlyAvailableColors.filter(col => col !== nextColors.box2);
nextColors.box3 = getRandomOption(colors.box3, currentlyAvailableColors)
currentlyAvailableColors = currentlyAvailableColors.filter(col => col !== nextColors.box3);
nextColors.box4 = getRandomOption(colors.box4, currentlyAvailableColors)
currentlyAvailableColors = currentlyAvailableColors.filter(col => col !== nextColors.box4);
setCurrentColours({ ...nextColors });
};
这是一个工作的相互依赖https://codepen.io/yftachman/pen/XWZMqVZ