I am trying to make a Sudoku solver. I have a parent component Board
and a child component Possible
which shows available options for any box in the board. I passed the state of board,selected
(selected box position in the board) and function to update board as props. But when I try to change board
from Possible
it doesn't change unless the selected box selected
is changed from parent component. I am trying to change board
element from child component.
Here is my Board
component.
import React, { useState } from 'react';
import Possibles from './avails.jsx';
import solve, { initBoard } from '../help';
function Board() {
const [msg, setmsg] = useState('');
const [solved, setSolved] = useState(false);
const [grid, setGrid] = useState(initBoard());
const [selected, setSelected] = useState([0, 0]);
const solveBoard = () => {
const solution = solve(grid);
setGrid(solution);
setSolved(true);
let a = true;
for (let i = 0; i < 9; i ) {
for (let j = 0; j < 9; j ) {
// console.log(i,j)
if (grid[i][j] === 0) {
// console.log(grid[i][j]);
a = false;
}
}
}
if (!a) {
setmsg('Invalid Board!');
} else setmsg('Here is your solution!');
};
const updatePosition = (row, col) => {
setSelected([row, col]);
};
const resetBoard = () => {
setGrid(initBoard());
setSolved(!solved);
setmsg('');
};
return (
<div className="board">
Sudoku Solver
{grid.map((row, index) => (
<div key={index} className="row">
{row.map((el, i) => (
<button
type="button"
key={i}
className={selected[0] === index && selected[1] === i ? 'el selected' : 'el'}
onClick={() => { updatePosition(index, i); }}
>
{el === 0 ? '' : el}
</button>
))}
</div>
))}
{setSolved
? <Possibles board={grid} pos={selected} setGrid={setGrid} setPos = {setSelected}/> : ''}
<button type="button" className="btn" onClick={solveBoard}>Solve</button>
<button type="button" className="btn" onClick={resetBoard}>Reset</button>
<div>{msg}</div>
</div>
);
}
export default Board;
And here is my child component Possibles
.
import React, { useState, useEffect } from 'react';
import { getAvailableNumbers } from '../help';
function Possibles({ board, pos, setGrid }) {
const [possibles, setPosibles] = useState([]);
useEffect(() => {
const avails = getAvailableNumbers(board, pos);
avails.unshift(0);
setPosibles(avails, board, possibles);
}, [pos,board]);
const updateGrid = (opt) => {
// setPosibles((prev) => prev.filter((x) => x !== opt || x === 0));
board[pos[0]][pos[1]] = opt;
setGrid(board);
};
return (
<div>
{possibles.map((opt) => (
<button type="button" key={opt} onClick={() => { updateGrid(opt); }}>{opt === 0 ? 'X' : opt}</button>
))}
</div>
);
}
export default Possibles;
CodePudding user response:
please change your 'updateGrid'
function to -
const updateGrid = (opt) => {
// setPosibles((prev) => prev.filter((x) => x !== opt || x === 0));
board[pos[0]][pos[1]] = opt;
board = [...board]; // this will make parent component rerender
setGrid(board);
};
input to setPosibles should be an array according to first line of 'Possibles'
component -
setPosibles(avails, board, possibles);
Edit - react basically uses shallow comparison for props, state
to detect new available change. By using a spread operator
we are a creating new array with a new memory location, this let react know about new change and rerendering is triggered.