【问题标题】:React Hook for re-rendering state updated by asynchronous recursive functionReact Hook 用于重新渲染由异步递归函数更新的状态
【发布时间】:2020-08-15 22:54:46
【问题描述】:

我正在构建一个反应应用程序,它可以解决数独问题并可视化解决算法。

我正在尝试将类组件转换为功能组件,但不确定如何使状态更改生效。

有问题的代码是:

  async solve() {
    await this.sleep(0);
    const board = this.state.board;
    for (let row = 0; row < 9; row++) {
      for (let col = 0; col < 9; col++) {
        if (board[row][col] !== 0) {
          // can't change filled cells
          continue;
        }
        // try 1 to 9 for the empty cell
        for (let num = 1; num <= 9; num++) {
          if (App.isValidMove(board, row, col, num)) {
            // valid move, try it
            board[row][col] = num;
            this.setState({ board: board });
            if (await this.solve()) {
              return true;
            } else {
              // didn't solve with this move, backtrack
              board[row][col] = 0;
              this.setState({ board: board });
            }
          }
        }
        // nothing worked for empty cell, must have deprived boards solution with a previous move
        return false;
      }
    }
    // all cells filled
    return true;
  }

(Full code hereapp is hosted here)

这里我需要async,所以我可以使用sleep() 来可视化算法。我使用this.setState({ board: board }); 来触发每次板子发生变异时的重新渲染。


当我尝试转换为功能组件时:

  • useState 钩子,我使用了 const [board, setBoard] = useState(initialBoard); 并将 this.setState 调用替换为 setBoard(board)。这不起作用,因为钩子是called in a loop
  • useEffect 包裹useState(即useEffect(() =&gt; setBoard(board), [board]))。这没有编译,得到错误React Hook "useEffect" may be executed more than once...
  • 也查看了useReducer,但有read it doesn't work well with async

我的问题是:

  • 这甚至可以转换为功能组件吗?
  • 如果是,我应该使用什么钩子?是否需要重新设计我的 solve() 函数?
  • 是否最好将其从类组件转换为函数组件?

【问题讨论】:

  • 嘿,你试过useAsyncEffect而不是useEffect吗?每当我有这样的异步钩子时,我都会使用这个 npm 包npm link

标签: reactjs react-hooks react-component react-functional-component use-state


【解决方案1】:

您可以在每次板子更改时使用效果,此效果将运行。当没有更多动作时,棋盘不会改变,效果也不会运行。

下面是一个示例,说明如何做到这一点:

const { useState, useEffect } = React;
const getCell = (board) => {
  const row = board.findIndex((row) =>
    row.some((cell) => !cell.checked)
  );
  if (row === -1) {
    return [-1, -1, false];
  }
  const col = board[row].findIndex((cell) => !cell.checked);
  return [row, col, true];
};
const initialState = [
  [{ checked: false }, { checked: false }],
  [{ checked: false }, { checked: false }],
];
const App = () => {
  const [board, setBoard] = useState(initialState);
  useEffect(() => {
    const timer = setTimeout(
      () =>
        setBoard((board) => {
          const [row, col, set] = getCell(board);
          if (set) {//do we need to set board (there are moves)
            const boardCopy = [...board];
            boardCopy[row] = [...board[row]];
            boardCopy[row][col] = {
              ...boardCopy[row][col],
              checked: true,
            };
            return boardCopy;
          }
          //this will return the same as passed in
          //  so App will not re render because board
          //  will not have changed
          return board;//no moves left because set is false
        }),
      1000
    );
    return () => clearTimeout(timer);
  }, [board]);
  return (
    <div>
      <button onClick={() => setBoard(initialState)}>
        reset
      </button>
      <table>
        <tbody>
          {board.map((row, i) => (
            <tr key={i}>
              {row.map(({ checked }, i) => (
                <td key={i}>{checked ? 'X' : 'O'}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>

【讨论】:

    【解决方案2】:

    可以使用 useState 钩子。

    问题是我没有正确复制电路板;需要使用const boardCopy = [...board];(而不是const boardCopy = board)。

    Full code of the functional component is here.

    Previous class component code is here.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-09
      • 1970-01-01
      • 2016-11-04
      • 2021-09-16
      • 2020-09-05
      相关资源
      最近更新 更多