我想使用 React with hooks 随机化 css 类 网格中的项目
I want to randomize the css classes the items in a grid using React with hooks
我在 React 中创建了一个网格组件。我有一个名为 'availableColors' 的字符串数组,其中存储了我想使用的 css class 名称。
在 'RandomColorGrid' 组件中,我设置 'useState' 中每个网格项目的初始颜色,为每个项目分配 'availableColors' 的索引。
网格中的每个项目都会调用 'changeColors()' onClick。在该方法中,我使用从 'availableColors'.
中随机选择的新索引重新分配 'colors' 中每个 'box' 的值
这很好用,但感觉有点笨拙。有两件事我想改进,但卡住了。
首先;我想在调用 'changeColors()' 函数时只使用每种颜色一次。目前,可以在多个网格项目上使用相同的颜色,我希望它们每次都是四种不同的颜色。
第二;我不希望任何物品连续两次出现相同的颜色。因此,对于任何给定的项目,我会从可能的随机选择中排除该项目的当前颜色。
我一直在尝试通过获取当前颜色的颜色索引并形成一个新的颜色数组来实现这一点,以便从每个项目中随机 select 然后另一个数组来尝试跟踪颜色已经被使用以避免重复,但这样做却陷入了真正的混乱。这让我相信我的设计可能从一开始就很糟糕。
我该如何改进?
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
我在 React 中创建了一个网格组件。我有一个名为 'availableColors' 的字符串数组,其中存储了我想使用的 css class 名称。
在 'RandomColorGrid' 组件中,我设置 'useState' 中每个网格项目的初始颜色,为每个项目分配 'availableColors' 的索引。
网格中的每个项目都会调用 'changeColors()' onClick。在该方法中,我使用从 'availableColors'.
中随机选择的新索引重新分配 'colors' 中每个 'box' 的值这很好用,但感觉有点笨拙。有两件事我想改进,但卡住了。
首先;我想在调用 'changeColors()' 函数时只使用每种颜色一次。目前,可以在多个网格项目上使用相同的颜色,我希望它们每次都是四种不同的颜色。
第二;我不希望任何物品连续两次出现相同的颜色。因此,对于任何给定的项目,我会从可能的随机选择中排除该项目的当前颜色。
我一直在尝试通过获取当前颜色的颜色索引并形成一个新的颜色数组来实现这一点,以便从每个项目中随机 select 然后另一个数组来尝试跟踪颜色已经被使用以避免重复,但这样做却陷入了真正的混乱。这让我相信我的设计可能从一开始就很糟糕。
我该如何改进?
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