I want to generate a 16-length array of random prizes using prizes
array that is passed as a prop in Board
component, and display them.
prizes
array -
[
{
prizeId: 1,
name: 'coupon',
image: 'img/coupon.svg',
},
{
prizeId: 2,
name: 'gift card',
image: 'img/gift-card.svg',
},
// more prizes
]
In Board.js
-
const Board = ({ prizes }) => {
const [shuffledPrizes, setShuffledPrizes] = useState(null)
useEffect(() => {
setShuffledPrizes(shuffleArray(populatePrize(16, prizes)))
}, [prizes])
return (
<div>
{
shuffledPrizes && shuffledPrizes.map((prize) => (
<Prize
key={prize.id}
prize={prize}
/>
))
}
</div>
)
}
In populatePrize
function, I have to add id
to use as React key because already existed prizeId
can't be used, as prizes will be duplicated -
import { nanoid } from 'nanoid'
const populatePrize = (noOfBlock, prizeArray) => {
const arrayToPopulate = []
let index = 0
for (let i = 0; i < noOfBlock; i += 1, index += 1) {
if (index === prizeArray.length) {
index = 0
}
arrayToPopulate.push({
id: nanoid(),
prizeId: prizeArray[index].prizeId,
name: prizeArray[index].name,
image: prizeArray[index].image,
})
}
return arrayToPopulate
}
Is using useState and useEffect necessary here? Because, I don't think generating an array and shuffling it is a side effect, and I can just use a variable outside of Board
function like -
let shuffledPrizes = null
const Board = ({ prizes }) => {
if (!shuffledPrizes)
shuffledPrizes = shuffleArray(populatePrize(16, prizes))
}
return (
<div>
{
shuffledPrizes.map((prize) => (
<Prize
key={prize.id}
prize={prize}
/>
))
}
</div>
)
}
But, with that way, every <Board />
component references and display the same shuffledPrizes
array, not randomly for each Board
component like I want.
Reusing Board
is not a requirement, but I read in React docs about components being pure functions and I don't think mine is one. I am also confused in when to use a variable outside or inside of a component, and when to use state.
Although my question might be about using useEffect, I want to learn how to improve this code in proper React way.
This in indeed not a good use case of useEffect.
Effects are an escape hatch from the React paradigm. They let you “step outside” of React and synchronize your components with some external system like a non-React widget, network, or the browser DOM. If there is no external system involved (for example, if you want to update a component’s state when some props or state change), you shouldn’t need an Effect. Removing unnecessary Effects will make your code easier to follow, faster to run, and less error-prone.
You can shuffle the array when you pass it trough props.
const BoardContainer = () => <div>
<Board prizes={shuffleArray(populatePrize(16, prices))}/>
<Board prizes={shuffleArray(populatePrize(16, prices))}/>
</div>
You can also use the lazy version of useState that is only evaluated during the first render
const Board = ({prizes}) => {
const [shuffledPrizes,] = useState(() => shuffleArray(populatePrize(16, prizes)))
return (
<div>
<ul>
{
shuffledPrizes && shuffledPrizes.map((prize) => (
<Prize
key={prize.id}
prize={prize}
/>
))
}
</ul>
</div>
)
}