Я новичок в redux и задаюсь вопросом, правильно ли я его использую

Это карточная военная игра. Я новичок в redux и задаюсь вопросом, правильно ли я его использую, особенно когда я объявляю действия в компонентах Game и Main и использую полезные нагрузки действий в качестве обратных вызовов для обновления состояния. Кажется, что для небольшого приложения нужно много кода. Может, вы поможете ребятам и поделитесь со мной своими мыслями, спасибо.

store.js:

import { createStore } from "redux";

const state = {
  game_ready: false,
  cards: [],
  player: { name: "", cards: [], points: 0 },
  computer: { name: "computer", cards: [], points: 0 },
};

const reducer = (state, action) => {
  switch (action.type) {
    case "INIT_GAME_CARDS":
      return action.payload(state);
    case "UPDATE_PLAYER_NAME":
      return action.payload(state);
    case "SET_GAME_READY":
      return action.payload(state);
    case "DIST_CARDS":
      return action.payload(state);
    case "SET_NEXT_CARDS":
      return action.payload(state);
    case "INCREASE_POINTS":
      return action.payload(state);
    case "RESET_GAME":
      return action.payload(state);
    default:
      return state;
  }
};

const store = createStore(reducer, state);

export default store;

Main.js:

import React, { useEffect } from "react";
import { Button } from "@material-ui/core";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { NUM_OF_CARDS, MAX_CARD_VALUE } from "./constants";
import { shuffle } from "./helpers";

// action creator to initialize the game
const initGameCards = () => ({
  type: "INIT_GAME_CARDS",
  payload: (state) => {
    // creates an array of size 52 filled with 1..13 four times
    const cards = Array(NUM_OF_CARDS / MAX_CARD_VALUE)
      .fill(
        Array(13)
          .fill()
          .map((_, i) => i + 1)
      )
      .flat();
    // shuffle the cards
    shuffle(cards);
    return {
      ...state,
      cards,
    };
  },
});

// action creator to control the player's name
const updatePlayerName = (name) => ({
  type: "UPDATE_PLAYER_NAME",
  payload: (state) => ({
    ...state,
    player: { ...state.player, name: name },
  }),
});

const setGameReady = () => ({
  type: "SET_GAME_READY",
  payload: (state) => ({
    ...state,
    game_ready: true,
  }),
});

function Main() {
  const history = useHistory();
  const dispatch = useDispatch();
  const player = useSelector(({ player }) => player);
  // const game_ready = useSelector(({ game_ready }) => game_ready);

  const handleClick = React.useCallback(
    (e) => {
      e.preventDefault();
      if (player.name) {
        dispatch(setGameReady());
        history.replace("./game");
      }
    },
    [dispatch, player.name]
  );

  useEffect(() => {
    dispatch(initGameCards());
  }, []);

  const handleChange = React.useCallback((e) => {
    const target = e.target;
    const val = target.value;
    switch (target.id) {
      case "playerName":
        dispatch(updatePlayerName(val));
        break;
      default:
        break;
    }
  });

  return (
    <div>
      {/* check for valid input */}
      <form>
        <label htmlFor="playerName">
          <h1 className="text-blue-800 text-5xl text-shadow-lg mb-3">
            Ready for war
          </h1>
        </label>
        <input
          className="border focus:ring-2 focus:outline-none"
          id="playerName"
          required
          onChange={handleChange}
          placeholder="Enter your name"
          type="text"
          value={player.name}
        />
        {!player.name ? (
          <p className="text-red-700">Please fill the field</p>
        ) : (
          ""
        )}
        <Button
          onClick={handleClick}
          type="submit"
          color="primary"
          variant="contained"
        >
          Start
        </Button>
      </form>
    </div>
  );
}

export default Main;

Game.js:

import { Button } from "@material-ui/core";
import React from "react";
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useHistory } from "react-router-dom";
import { NUM_OF_CARDS } from "./constants";
import { shuffle } from "./helpers";

// action creator to distribute the cards at the beginning of the game
const distCards = () => ({
  type: "DIST_CARDS",
  payload: (state) => {
    const cards = [...state.cards];
    shuffle(cards);
    const computer_cards = cards.slice(0, NUM_OF_CARDS / 2);
    const player_cards = cards.slice(NUM_OF_CARDS / 2);
    const computer_current_card = computer_cards.pop();
    const player_current_card = player_cards.pop();
    return {
      ...state,
      cards,
      // distributes cards evenly
      computer: {
        ...state.computer,
        cards: computer_cards,
        current_card: computer_current_card,
        points: 0,
      },
      player: {
        ...state.player,
        cards: player_cards,
        current_card: player_current_card,
        points: 0,
      },
    };
  },
});

const setNextCards = () => ({
  type: "SET_NEXT_CARDS",
  payload: (state) => {
    let [computer_cards, player_cards] = [
      [...state.computer.cards],
      [...state.player.cards],
    ];
    const [computer_next_card, player_next_card] = [
      computer_cards.pop(),
      player_cards.pop(),
    ];
    return {
      ...state,
      player: {
        ...state.player,
        cards: player_cards,
        current_card: player_next_card,
      },
      computer: {
        ...state.computer,
        cards: computer_cards,
        current_card: computer_next_card,
      },
    };
  },
});

const pointsIncreament = () => ({
  type: "INCREASE_POINTS",
  payload: (state) => {
    const [player_current_card, computer_current_card] = [
      state.player.current_card,
      state.computer.current_card,
    ];
    return {
      ...state,
      player: {
        ...state.player,
        points:
          player_current_card > computer_current_card
            ? state.player.points + 1
            : state.player.points,
      },
      computer: {
        ...state.computer,
        points:
          player_current_card < computer_current_card
            ? state.computer.points + 1
            : state.computer.points,
      },
    };
  },
});

function Game() {
  const player = useSelector(({ player }) => player);
  const computer = useSelector(({ computer }) => computer);
  const game_ready = useSelector(({ game_ready }) => game_ready);
  const dispatch = useDispatch();
  const history = useHistory();
  const handleReset = React.useCallback(() => {
    dispatch(distCards());
  }, [dispatch]);

  useEffect(() => {
    if (game_ready) {
      dispatch(distCards());
    } else {
      history.replace("/");
    }
  }, [game_ready]);

  useEffect(() => {
    if (player.current_card && computer.current_card) {
      dispatch(pointsIncreament());
    }
  }, [player.current_card, computer.current_card]);

  const handleClick = React.useCallback(() => {
    dispatch(setNextCards());
  });

  return (
    <div className="flex justify-center">
      <div className="flex flex-col">
        <div>
          <div>{player.name}</div>
          <div>Points: {player.points}</div>
          <div>{player.current_card}</div>
        </div>
        <div>
          <div>{computer.current_card}</div>
          <div>Points: {computer.points}</div>
          <div>{computer.name}</div>
        </div>
        {!player.cards.length || !computer.cards.length ? (
          <Button
            onClick={handleReset}
            type="submit"
            color="primary"
            variant="contained"
          >
            Again?
          </Button>
        ) : (
          <Button
            onClick={handleClick}
            type="submit"
            color="primary"
            variant="contained"
          >
            next
          </Button>
        )}
        <div>
          {!player.cards.length || !computer.cards.length ? (
            player.points === computer.points ? (
              <h2>It's a tie</h2>
            ) : player.points > computer.points ? (
              <h2>{player.name} won!</h2>
            ) : (
              <h2>{computer.name} won!</h2>
            )
          ) : (
            ""
          )}
        </div>
      </div>
    </div>
  );
}

export default Game;

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *