States not updating - javascript

I'm coding a sorting visualizer in ReactJS, and I use a state to hold the delay between each render.
When I change the slider of the delay, the sorting does not update.
I made it log the updated value, and in each loop I made it log the value it reads.
for some reason, when I read the getDelay inside the loop, and outside of it, they are different.
Here is the code:
import React, { useState, useEffect } from "react";
import "./SortingVisualizer.css";
class Bar {
constructor(value, className) {
this.value = value;
this.className = className;
}
}
const SortingVisualizer = () => {
const [getArray, setArray] = useState([Bar]); //array to hold the bars
const [getSlider, setSlider] = useState(50);
const [getDelay, setDelay] = useState(2);
//reset the array at the start
useEffect(() => {
resetArray(10);
}, []);
//function to reset the array
const resetArray = () => {
const array = [];
for (let i = 0; i < getSlider; i++) {
array.push(new Bar(randomInt(20, 800), "array-bar"));
}
setArray(array);
};
//a delay function. use like this: `await timer(time to wait)`
const timer = delay => {
return new Promise(resolve => setTimeout(resolve, delay));
};
//function to do buuble sort with given delay between each comparison
const bubbleSort = async () => {
let temp,
array = Object.assign([], getArray); // defining a temporary variable, and a duplicate array the the bars array
//looping from the array size to zero, in cycles
for (let i = array.length; i > 0; i--) {
//looping from the start of the section from the first loop to the end of it.
for (let j = 0; j < i - 1; j++) {
//changing the colors of the compared bares
array[j].className = "array-bar compared-bar";
array[j + 1].className = "array-bar compared-bar";
if (getDelay > 0) await timer(getDelay / 2);
setArray([...array]);
//comparing and switching if needed
if (array[j].value > array[j + 1].value) {
temp = array[j].value;
array[j].value = array[j + 1].value;
array[j + 1].value = temp;
setArray([...array]);
}
//updating the array and moving to the next pair
if (getDelay > 0) await timer(getDelay / 2);
array[j].className = "array-bar";
array[j + 1].className = "array-bar";
// Wait delay amount in ms before continuing, give browser time to render last update
}
array[i - 1].className = "array-bar completed-bar";
}
setArray([...array]);
console.log("done.");
};
const combSort = async () => {
let temp,
swapped,
array = Object.assign([], getArray); // defining a temporary variable, and a duplicate array the the bars array
//looping from the array size to zero, in cycles
for (let i = array.length; i > 0; i = Math.floor(i / 1.3)) {
//looping from the start of the section from the first loop to the end of it.
swapped = false;
for (let j = 0; j < array.length - i; j++) {
//changing the colors of the compared bares
array[j].className = "array-bar compared-bar";
array[j + i].className = "array-bar compared-bar";
setArray([...array]);
await timer(getDelay / 2);
//comparing and switching if needed
if (array[j].value > array[j + i].value) {
temp = array[j].value;
array[j].value = array[j + i].value;
array[j + i].value = temp;
setArray([...array]);
swapped = true;
await timer(getDelay / 2);
}
//updating the array and moving to the next pair
array[j].className = "array-bar";
array[j + i].className = "array-bar";
// Wait delay amount in ms before continuing, give browser time to render last update
console.log(getDelay);
}
//array[i - 1].className = "array-bar completed-bar";
if (i === 1 && swapped) i = 2;
}
setArray([...array]);
};
const sliderUpdate = e => {
setSlider(e.target.value);
resetArray(getSlider);
};
const delayUpdate = e => {
setDelay(e.target.value * 1);
console.log(getDelay);
};
return (
<>
<div className="menu">
<button onClick={() => resetArray()}>Geneate new array</button>
<button onClick={() => bubbleSort()}>Do bubble sort</button>
<button onClick={() => combSort()}>Do comb sort</button>
</div>
<div class="slide-container">
<input
type="range"
min="3"
max="250"
value={getSlider}
class="slider"
id="sizeSlider"
onChange={sliderUpdate}
/>
<input
type="range"
min="0"
max="1000"
value={getDelay}
class="slider"
id="delaySlider"
onChange={delayUpdate}
/>
</div>
<div className="array-container">
{getArray.map((bar, i) => (
<div
className={getArray[i].className}
key={i}
style={{ height: `${bar.value * 0.1}vh` }}
></div>
))}
</div>
</>
);
};
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export default SortingVisualizer;

I don't know what the best solution is, but a solution would be to use useRef.
The problem is related to Why am I seeing stale props or state inside my function? : On each render you are creating new functions for bubbleSort and combSort. Those functions use the value of getDelay that existed at the moment those functions have been created. When one of the buttons is clicked the "version" of the function of the last render will be executed, so the value of getDelay that existed then and there will be used.
Now, changing the slider will cause a rerender, and thus new versions of bubbleSort and combSort are created ... but those are not the versions that are currently running!
useRef solves that problem because instead of directly referring to the delay, we are referring to an object whose current property stores the delay. The object doesn't change, but the current property does and every time it's accessed we get the current value. I highly encourage you to read the documentation.
After your state variables, add
const delayRef = useRef(getDelay);
delayRef.current = getDelay
The second line keeps the ref in sync with the state.
Everywhere else where you reference getDelay, except value of the slider itself, use delayRef.current instead. For example:
if (delayRef.current > 0) await timer(delayRef.current / 2);
Demo (couldn't get it to work on SO): https://jsfiddle.net/wuf496on/

Related

Cell Component not re-rendering on Board in React

Edit
I was able to start getting the cells to rerender, but only after adding setCellsSelected on line 106. Not sure why this is working now, react is confusing.
Summary
Currently I am trying to create a visualization of depth first search in React. The search itself is working but the cell components are not re-rendering to show that they have been searched
It starts at the cell in the top left and checks cells to the right or down. Once a cell is searched, it should turn green. My cells array state is changing at the board level, so I assumed that the board would re-render but to no avail. For now I am only searching the cells straight below (0,0) as a test.
Code
Board.js
const Cell = (props) => {
let cellStyle; // changes based on props.value
if (props.value === 3) cellStyle = "cell found";
else if (props.value === 2) cellStyle = "cell searched";
else if (props.value === 1) cellStyle = "cell selected";
else cellStyle = "cell";
return <div className={cellStyle} onClick={() => props.selectCell()}></div>;
};
const Board = () => {
// 0 = not searched
// 1 = selected
// 2 = searched
// 3 = selected found
const [cells, setCells] = useState([
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
new Array(10).fill(0),
]); // array of cells that we will search through, based on xy coordinates
const [start, setStart] = useState("00");
const selectCell = (x, y) => {
// Make sure to copy current arrays and add to it
let copyCells = [...cells];
copyCells[x][y] = 1;
setCells(copyCells);
};
const renderCell = (x, y) => {
return (
<Cell
key={`${x}${y}`}
value={cells[x][y]}
selectCell={() => selectCell(x, y)}
/>
);
};
const renderBoard = () => {
let board = [];
for (let i = 0; i < cells.length; i++) {
let row = [];
for (let j = 0; j < cells.length; j++) {
let cell = renderCell(i, j);
row.push(cell);
}
let newRow = (
<div className="row" key={i}>
{row}
</div>
);
board.push(newRow);
}
return board;
};
const startSearch = () => {
// start with our current startingCell
const startX = parseInt(start[0]);
const startY = parseInt(start[1]);
let copyCells = [...cells];
const searchCell = (x, y) => {
console.log("Coordinate:", x, y);
if (x >= cells.length) return;
if (y >= cells.length) return;
let currentCell = copyCells[x][y];
console.log(copyCells);
if (currentCell === 1) {
copyCells[x][y] = 3;
console.log("Found!");
console.log(x, y);
return;
} else {
console.log("Not Found");
copyCells[x][y] = 2;
setTimeout(() => {
searchCell(x + 1, y);
}, 3000);
setTimeout(searchCell(x, y + 1), 3000);
}
setCells(copyCells);
setCellsSelected(['12']) // this works for some reason
};
searchCell(startX, startY);
};
return (
<>
<div style={{ margin: "25px auto", width: "fit-content" }}>
<h3>Change search algorithm here!</h3>
<button onClick={() => startSearch()}>Start</button>
</div>
<div className="board">{renderBoard()}</div>
</>
);
};
export default Board;
You have two issues:
working demo: https://codesandbox.io/s/wonderful-cartwright-qldiw
The first issue is that you are doing setStates inside a long running function. Try instead keeping a search state and update the location instead of calling recursively.
The other issue is at the selectCell function
you are copying the rows by reference(let copyCells = [...cells];), so when you change the cell (copyCells[x][y] = 1;) you are also changing the original row, so the diffing will say the state did not change.
const selectCell = (x, y) => {
// Make sure to copy current arrays and add to it
let copyCells = [...cells];
copyCells[x][y] = 1;
setCells(copyCells);
};
try changing to let copyCells = [...cells.map(row=>[...row])];

How to work around updating state multiple times in a for loop? ReactJS

I am trying to use a for loop in order to run a function 10 times, which relies on the previous state to update. I know I am not supposed to setState in a loop since state changes are batched, so what are my options if I want to run the function 10 times with a single click handler? I am using hooks (useState), if that matters.
Below is my relevant code :
export default function Rolls(props) {
const [roll, setRoll] = useState(null)
const [tenPityCount, setTenPityCount] = useState(0)
const [ninetyPityCount, setNinetyPityCount] = useState(0)
// handler for single roll
const handleSingleRoll = () => {
// sets the main rolling RNG
const rng = Math.floor(Math.random() * 1000) +1
// pulls a random item from the data set for each star rating
const randomFiveStar = Math.floor(Math.random() * fiveStarData.length)
const randomFourStar = Math.floor(Math.random() * fourStarData.length)
const randomThreeStar = Math.floor(Math.random() * threeStarData.length)
// check if ten pity count has hit
if (tenPityCount === 9) {
setRoll(fourStarData[randomFourStar].name)
setTenPityCount(0)
return;
}
// check if 90 pity count has hit
if (ninetyPityCount === 89) {
setRoll(fiveStarData[randomFiveStar].name)
setNinetyPityCount(0)
return;
}
// check if rng hit 5 star which is 0.6%
if (rng <= 6) {
setRoll(fiveStarData[randomFiveStar].name)
setNinetyPityCount(0)
// check if rng hit 4 star which is 5.1%
} else if (rng <= 51) {
setRoll(fourStarData[randomFourStar].name)
setTenPityCount(0)
// only increment for 90 pity counter b/c 10 pity resets upon hitting 4 star
setNinetyPityCount(prevState => prevState +1)
// anything else is a 3 star
} else {
setRoll(threeStarData[randomThreeStar].name)
// pity counter increment for both
setTenPityCount(prevState => prevState + 1)
setNinetyPityCount(prevState => prevState +1)
}
}
const handleTenRoll = () => {
for (let i = 0; i < 10; i++) {
handleSingleRoll()
}
}
return (
<>
<div>
<span>
<button onClick={handleSingleRoll} className='btn btn-primary mr-2'>Wish x1</button>
<button onClick={handleTenRoll} className='btn btn-primary mr-2'>Wish x10</button>
<button className='btn btn-danger'>Reset</button>
</span>
</div>
</>
)
}
My suggestion would be to use a proxy functions:
const [roll, setRollState] = useState(null)
const [tenPityCount, setTenPityCountState] = useState(0)
const [ninetyPityCount, setNinetyPityCountState] = useState(0)
const newState = useRef({});
const consolidatedUpdates = useRef({setRollState, setTenPityCountState, setNinetyPityCountState})
function presetStateUpdate(name, state){
newState.current[name] = state
}
function pushPresetState(){
Object.entries(newState.current).forEach(([fnName, value]) => {
const fn = consolidatedUpdates[fnName];
if(typeof fn == 'function') fn(value);
});
newState.current = {};
}
const setRoll = v => presetStateUpdate('setRoll', v);
const setTenPityCount = v => presetStateUpdate('setTenPityCount', v);
const setNinetyPityCount = v => presetStateUpdate('setNinetyPityCount', v);
respectively:
const handleTenRoll = () => {
for (let i = 0; i < 10; i++) {
handleSingleRoll()
}
pushPresetState()
}

i have issues regarding react state

Hi i have been building a sorting algorithms visualization it works so far but i have a doubt regarding state object.
consider the below code:
import React,{Component} from 'react';
import getMergeSortAnimations from './Person/Person';
import bubbleSortAnimations from './Person/BubbleSort';
import './App.css';
class App extends Component{
state = {
array: [],
bar_width:2
};
componentDidMount() {
this.generateArray();
}
generateArray = ()=> {
const array = [];
let val = document.querySelector('#size').value;
if(val<=10)
{
this.setState({bar_width:8});
}
else if(val<=20 && val>10)
this.setState({bar_width:7});
else if(val<=50 && val>20)
this.setState({bar_width:6});
else if(val<=100 && val>50)
this.setState({bar_width:5});
else if(val<=150 && val>100)
this.setState({bar_width:3});
else
this.setState({bar_width:2});
for (let i = 0; i < val; i++) {
array.push(this.randomIntFromInterval(5, 450));
}
this.setState({array});
}
randomIntFromInterval = (min, max)=> {
return Math.floor(Math.random() * (max - min + 1) + min);
}
mergeSort = ()=>{
let t ;
console.log(this.state);
const animations = getMergeSortAnimations(this.state.array);
console.log(this.state);
for (let i = 0; i < animations.length; i++) {
const arrayBars = document.getElementsByClassName('element');
const isColorChange = i % 3 !== 2;
if (isColorChange) {
const [barOneIdx, barTwoIdx] = animations[i];
const barOneStyle = arrayBars[barOneIdx].style;
const barTwoStyle = arrayBars[barTwoIdx].style;
const color = i % 3 === 0 ? 'red' : '#007bff';
setTimeout(() => {
barOneStyle.backgroundColor = color;
barTwoStyle.backgroundColor = color;
}, i*10);
} else {
setTimeout(() => {
const [barOneIdx, newHeight] = animations[i];
const barOneStyle = arrayBars[barOneIdx].style;
barOneStyle.height = `${newHeight}px`;
}, i*10);
}
}
}
render() {
return (
<div>
<header>
<input className="slider" onChange={this.generateArray} type="range" min="5" max="200"
id='size'/>
<nav>
<ul>
<li><button onClick={this.generateArray} id="new" >New array</button></li>
<li><button onClick={this.mergeSort} id="mergesort" >Merge Sort</button></li>
<li><button onClick={this.bubbleSort} id="bubbleSort" >Bubble sort</button></li>
</ul>
</nav>
</header>
<div className="container">
<br></br>
{this.state.array.map((value, idx) => (
<div
className="element"
key={idx}
style={{
width:`${this.state.bar_width}px`,
height:`${value}px`
}}></div>
))}
</div>
</div>
);
}
}
Merge sort Code:
export default function getMergeSortAnimations(array) {
const animations = [];
mergeSort(array, 0, array.length - 1,animations);
return animations;
}
function mergeSort(array,low, high,animations) {
if(low<high)
{
const mid = Math.floor((low + high) / 2);
mergeSort(array, low, mid,animations);
mergeSort(array, mid + 1, high,animations);
merge(array, low, high,animations);
}
}
function merge(array,low,high,animations) {
let a = [];
let k = low;
let i = low;
let mid = Math.floor((low+high)/2);
let j = mid + 1;
while (i <= mid && j <= high) {
animations.push([i, j]);
animations.push([i, j]);
if (array[i] <= array[j]) {
animations.push([k, array[i]]);
a[k++] = array[i++];
} else {
animations.push([k, array[j]]);
a[k++] = array[j++];
}
}
while (i <= mid) {
animations.push([i, i]);
animations.push([i, i]);
animations.push([k, array[i]]);
a[k++] = array[i++];
}
while (j <= high) {
animations.push([j, j]);
animations.push([j, j]);
animations.push([k, array[j]]);
a[k++] = array[j++];
}
for(let o=low;o<k;o++)
{
array[o] = a[o];
}
}
The merge sort function is under src->Person->Person as mentioned in the import section,it just returns animations array which i use for visualization.
Now the generateArray function generates an array and sets it to state using setSate() Method.When this is done the user can select mergesort and the code runs.But as you can see getMergesortAnimations() returns the animations array after the actual mergesort happens.But the question is:
"""When i console the state array before calling getMergesortAnimations() it displays a sorted array.It happens even before the mergesort is called and how is the state set to the sorted array without acutally using setState method?"""
This is very confusing to me ....
Thanks.
// From Generate random number between two numbers in JavaScript
export default App;
From a quick look at your code I can see that at the very end of your mergeSort function you are doing:
for(let o=low;o<k;o++)
{
array[o] = a[o];
}
Which is modifying the array in place. So after you in your component call:
const animations = getMergeSortAnimations(this.state.array);
this.state.array will be modified in place. This is something you should not do in React, from React docs:
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
In order to fix this just fix the last couple lines of your mergeSort function so that it does not assign to array but rather creates a new array and returns that.

Shuffle array automatically 5 times

I have written JavaScript function, to shuffle an array of divs onClick.
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
// Button as an FYI
<button onClick={this.shuffle} className="has-text-black">shuffle hats</button>
This works absolutely fine, and randomises every time I click the button.
However, I want the divs to sort/shuffle 5 times automatically, onClick.
(IE = I don't want to have to click 5 times, to shuffle 5 times).
What's the best approach to do this?
(I've searched but haven't found anything to repeat shuffling on elements).
I thought about using async await/settimeout, to repeat this.state.divs.sort(() => Math.random() - .50) 5 times?
UPDATE:
To add context, here is a codesandbox...
https://codesandbox.io/s/distracted-shape-ifsiv
When I click the shuffle button, you can see the hats only swap positions once. Not 5 times.
Here is a posible way to do it, with javascript.
hats object get shuffled 5 times, with 200ms second transition.
Of course it's very simple, the object is meant to be extended!
let hats = [
{content: `<h6>1🎩</h6>`},
{content: `<h3>2🎩</h3>`},
{content: `<h1>3🎩</h1>`},
{content: `<h2>4🎩</h2>`},
{content: `<h4>5🎩</h4>`}
];
let timer;
function loop5(){
let i = 0
clearInterval(timer)
timer = setInterval(function(){
shuffle()
if (i >= 5){
clearInterval(timer)
}
i++
}, 200)
}
function shuffle(){
hats.sort(() => Math.random() - 0.5)
out.innerHTML = hats.map(e => e.content).join("")
}
div {display: flex; font-size: xx-large }
<button onclick="loop5()">shuffle hats</button>
<div id="out"></div>
I don't see why shuffling 5 times is better or any different than shuffling 5 times. Anyway you can do it in a naive way like this:
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
shuffleTimesFive = () => {
for(var i = 0; i < 5; i++)
this.shuffle();
}
// Button as an FYI
<button onClick={this.shuffleTimesFive} className="has-text-black">shuffle hats</button>
Or maybe a smarter way is to have a shuffleNTimes function that takes a parameter, like so:
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
shuffleNTimes = (n) => {
for(var i = 0; i < n; i++)
this.shuffle();
}
// Button as an FYI
<button onClick={this.shuffleNTimes.bind(this, 5)} className="has-text-black">shuffle hats</button>
I think shuffling one time and five times has the same effect, and Fisher-Yates is more efficient but keeping your way:
shuffle = () => {
let shuffled = [];
for(let i=0; i<5; i++)
shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
If you decide to use "Fisher-Yates" algorithm, you can implement it like:
const shuffle = () => {
let array = this.state.divs;
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
this.setState([...array]);
}
As I understood from your comment, you want to do animation, in this case you don't need a loop rather you can use setInterval() and reset it ones executed five times. I have written a demo on both shuffling ways, as you can see the method that uses sort() sometimes returns the same result while the "Fisher–Yates" always reshuffled.
<button onclick="shuffle()">Click To Shuffle</button>
<div id="1">div1</div>
<div id="2">div2</div>
<div id="3">div3</div>
<div id="4">div4</div>
<script>
//This one uses Fisher–Yates shuffle algorithm:
const divs = [...document.querySelectorAll('div')];
const shuffle = () => {
let count = 0;
const intervalId = setInterval( function() {
for (let i = divs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[divs[i], divs[j]] = [divs[j], divs[i]];
}
divs.forEach( div => document.body.appendChild(div) );
count++;
if(count === 5)
clearInterval(intervalId);
} ,1000)
}
</script>
<button onclick="shuffle()">Click To Shuffle</button>
<div id="1">div1</div>
<div id="2">div2</div>
<div id="3">div3</div>
<div id="4">div4</div>
<script>
const divs = [...document.querySelectorAll('div')];
shuffle = () => {
let shuffled = [];
let count = 0;
const intervalId = setInterval( function() {
shuffled = divs.sort(() => Math.random() - .50);
shuffled.forEach( div => document.body.appendChild(div) );
count++;
if(count === 5)
clearInterval(intervalId);
}, 1000 )
};
</script>
For your case, it would be like:
let divs = this.state.divs;
const shuffle = () => {
let count = 0;
const intervalId = setInterval( function() {
for (let i = divs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[divs[i], divs[j]] = [divs[j], divs[i]];
}
this.setState([...divs]);
count++;
if(count === 5)
clearInterval(intervalId);
} ,1000)
}

Shuffle an array of cards on click of a button

I want to be able to click on the button below and shuffle the cards in my card deck.
So far I have created an event listener which when clicked calls the function shuffleCards which takes an array. The array I have passed in is the one provided to me in the exercise which is an array of cards.
Nothing happens when I click on the button, I know it is something to do with scope but I do not know how to amend my code to make this work properly.
Thank you in advance.
HTML
<button type="button" id="shuffle" class="shuffle" class="btn btn-lg btn-secondary">Shuffle</button>
JAVASCRIPT
// Part given in exercise which creates a deck of cards:
const suit = 'hearts';
const cardsWrapper = document.querySelector('.cards-wrapper');
function createCards() {
const cards = [];
// Create an array with objects containing the value and the suit of each card
for (let i = 1; i <= 13; i += 1) {
const cardObject = {
value: i,
suit,
};
cards.push(cardObject);
}
// For each dataObject, create a new card and append it to the DOM
cards.forEach((card, i) => {
const positionFromLeft = i * 15;
const cardElement = document.createElement('div');
cardElement.setAttribute('data-value', card.value);
cardElement.classList.add('card', `${card.suit}-${card.value}`);
cardElement.style.left = `${positionFromLeft}px`;
cardsWrapper.append(cardElement);
});
}
// part written by me
const shufflebtn = document.getElementById('shuffle');
shufflebtn.addEventListener("click", () => {
shuffleCards(cards);
})
function shuffleCards(array) {
var i = 0
, j = 0
, temp = null
for (i = array.length - 1; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1))
temp = array[i]
array[i] = array[j]
array[j] = temp
}
return array
}
made some changes to code where i am not talking about html instead giving a solution for your card shuffle.
created a create cards button which triggers createCards function then, try clicking your shuffle and see console log you can see a shuffled array.
Note: click on create cards Button before you click on shuffle as you might log empty array
Also i changed the scope of cards as it should be accessible to other functions
const suit = 'hearts';
var cards = [];
function createCards() {
for (let i = 1; i <= 13; i += 1) {
const cardObject = {
value: i,
suit,
};
cards.push(cardObject);
}
}
const shufflebtn = document.getElementById('shuffle');
const creatorBtn = document.getElementById('creator');
shufflebtn.addEventListener("click", () => {
cards = shuffleCards(cards);
})
creatorBtn.addEventListener("click", () => {
createCards();
})
function shuffleCards(array) {
var i = 0,
j = 0,
temp = null
for (i = array.length - 1; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1))
temp = array[i]
array[i] = array[j]
array[j] = temp
}
console.log(array)
return array;
}
<button type="button" id="shuffle" class="shuffle" class="btn btn-lg btn-secondary">Shuffle</button>
<button type="button" id="creator" class="creator" class="btn btn-lg btn-secondary">create cards</button>

Categories