redux 在计算函数在类型脚本中调用的次数时出现的问题

iswrvxsc  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(92)

我是react和redux的初学者,我正在用这两个工具做一个井字游戏。
最近我遇到了一个新问题,那就是我的函数count++不能正常工作。
我会把整个代码放在问题的最后,但这是有问题的代码的摘要。

// my function which I want to count the times it's called by onClick event

let count = 0
  const handleTurn = (i: number, j: number) => {
    // this is the counter that doesn't work correctly
    count ++
    console.log(count)

    const newTurn = {
      i: i,
      j: j
    };
    const newGameStatus = {
      message: status
    }

    if (winner === null) {
      dispatch(turn(newTurn));
      dispatch(gameStatus(newGameStatus))
      
    }
  }

个字符
输出将是这样的(以红色突出显示):

的数据
但是当我删除了所有的内容,我的功能,它的工作正确

let count = 0
  const handleTurn = (i: number, j: number) => {
    count ++
    console.log(count)
  }


并且输出将是正确的:


我希望我的函数中的所有内容都正确,而且计数器也正确工作,我不知道我的函数或代码有什么问题。
我的整个代码(包括问题部分):

// store.ts

import { configureStore } from '@reduxjs/toolkit';
import tictactoeReducer from '../components/ticTacToeSlice';
import storage from 'redux-persist/lib/storage';
import { persistReducer, persistStore } from 'redux-persist';
import thunk from 'redux-thunk';

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, tictactoeReducer)

export const store = configureStore({
  reducer: {
    persistedReducer,
  },
  devTools: process.env.NODE_ENV !== 'production',
  middleware: [thunk]
});

export const persistor = persistStore(store)
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
// hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './store';

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
// ticTacToeSlice.ts

import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../app/store";

type Cell = 'X' | 'O' | '-'
type Table = Array<Array<Cell>>
type Turn = Exclude<Cell, '-'>

export interface State {
  move: string[]
  table: Table
  turn: Turn
  gameStatus: string
}

const initialState: State = {
  move: [],
  table: [
    ['-', '-', '-'],
    ['-', '-', '-'],
    ['-', '-', '-']
  ],
  turn: "X",
  gameStatus: "choose a box to start"
}

interface TurnAction {
  i: number,
  j: number,
}

interface GameStatusAction {
  message: string
}

interface moveAction {
  index: string[]
}

export const tictactoeSlice = createSlice({
  name: "tactactoe",
  initialState,
  reducers: {
    turn: (state, action: PayloadAction<TurnAction>) => {
      state.table[action.payload.i][action.payload.j] = state.turn
      state.turn = state.turn === 'O' ? 'X' : 'O'
    },
    move: (state, action: PayloadAction<moveAction>) => {
      state.move = action.payload.index
    },
    gameStatus: (state, action: PayloadAction<GameStatusAction>) => {
      state.gameStatus = action.payload.message
    },
    reset: () => initialState
  },
});

function calculateWinner(squares: Cell[]) {
  const lines = [
  // a, b, c 
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],

    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],

    [0, 4, 8],
    [2, 4, 6]
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] !== '-' && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

export const selectSquares = (state: RootState) => state.persistedReducer.table

export const selectWinner = createSelector(
  selectSquares,
  (squares) => {
    const squaresArray = squares.flat();
    return calculateWinner(squaresArray);
  }
);

export const { turn, reset, move, gameStatus } = tictactoeSlice.actions;
export const turnSelector = (state: RootState) => state.persistedReducer;
export default tictactoeSlice.reducer;
// ticTacToe.tsx

import { useEffect, useState } from "react";
import { useAppDispatch, useAppSelector } from "../app/hooks";
import { State, reset, selectWinner, gameStatus, turn, turnSelector } from "./ticTacToeSlice";

function TicTacToe() {

  const [states, setStates] = useState<State>();
  const selectedTurn = useAppSelector(turnSelector);
  const dispatch = useAppDispatch();
  const status = "game is on"
  

  useEffect(() => {
    setStates(selectedTurn);
  }, [selectedTurn]);

  let count = 0
  const handleTurn = (i: number, j: number) => {
    count ++
    console.log(count)
    const newTurn = {
      i: i,
      j: j
    };
    const newGameStatus = {
      message: status
    }

    if (winner === null) {
      dispatch(turn(newTurn));
      dispatch(gameStatus(newGameStatus))
      
    }
  }

  const winner = useAppSelector(selectWinner);

  return (
    <div className="container">
      <div>
        {winner === null ? (
          <div>

            {states?.turn === "X" ? (
              <h3>current turn: <span className="text-secondary">{states?.turn}</span></h3>
            ) : (
              <h3>current turn: <span className="text-danger">{states?.turn}</span></h3>
            )}

            <h3>{states?.gameStatus}</h3>

          </div>
        ) : (
          <h3>winner is <span className="text-success">{winner}</span></h3>
        )}
      </div>

      <table>
        <tbody>
          {states?.table.map((row, index) => {
            return (
              <tr key={index}>
                {row[0] === "-" ? (
                  <td className="paper-btn" onClick={() => { handleTurn(index, 0) }}>{row[0]}</td>
                ) : (
                  <td className="paper-btn">{row[0]}</td>
                )}

                {row[1] === "-" ? (
                  <td className="paper-btn" onClick={() => { handleTurn(index, 1) }}>{row[1]}</td>
                ) : (
                  <td className="paper-btn">{row[1]}</td>
                )}

                {row[2] === "-" ? (
                  <td className="paper-btn" onClick={() => { handleTurn(index, 2) }}>{row[2]}</td>
                ) : (
                  <td className="paper-btn">{row[2]}</td>
                )}
              </tr>
            )
          })}
        </tbody>
      </table>
      <br />

      <input type="button" className="paper-btn btn-primary-outline" value="Reset" onClick={() => dispatch(reset())} />

    </div>
  );
}

export default TicTacToe;
/* settings.css */

.disabled-btn {
    pointer-events: none;
}

(如果有语法错误,请见谅)

okxuctiv

okxuctiv1#

因为 * 在每次渲染 * 时,组件都会执行以下操作:

let count = 0

字符串
因此,每次都声明count并将其初始化为0。将此值与在多个渲染中成功持久化的值进行对比:

const [states, setStates] = useState<State>();


不同之处在于 state 的使用。若要在渲染之间保持count的值,请将其置于以下状态:

const [count, setCount] = useState(0);


然后,更新其状态,而不是直接递增count

const handleTurn = (i: number, j: number) => {
  setCount(count + 1);
  console.log(count + 1);
  //...

相关问题