Почему мое состояние не изменится правильно с помощью Redux? - PullRequest
0 голосов
/ 05 октября 2018

Я сделал игру Tic Tac Toe, пользователь против компьютера.Он прекрасно работает без использования Redux, но с тех пор, как в него встроен Redux, что-то не так.

Я пытаюсь добиться следующего: если есть пустой квадрат, то процессор случайным образом помещает O в пустом месте (после того, как пользователь поместил X), но на этот раз, используя Redux.

Я чувствую, что именно let turnState = this.props.turnValueReducerRedux(this.state.turn); является причиной проблемы и / или мой файл turnReducer.js неверен.

Я пометил // START HERE и // END HERE, чтобы указать, откуда, по моему мнению, может быть проблема.

Что я делаю не так и как я могу это исправить?

Вот Board.js

import React, { Component } from 'react';
import './Board.css';
import { connect } from 'react-redux';
import * as actionTypes from '../../store/actions/actions';

class Board extends Component {
    constructor(props) {
        super(props);
        this.state = {
            winner: undefined,
        };

        this.gameState = {
            turn: 'X',
            gameLocked: false,
            gameEnded: false,
            board: Array(9).fill(''),
            totalMoves: 0
        }

        this.clicked = this.clicked.bind(this);
    }


    clicked(box) {
        if(this.gameState.gameEnded || this.gameState.gameLocked) {
            return;
        }

        // START HERE 
        let turnState = this.props.turnValueReducerRedux(this.gameState.turn);

        if(this.gameState.board[box.dataset.square] === '') {
            this.gameState.board[box.dataset.square] = turnState;
            box.innerText = this.gameState.turn;

            this.gameState.turnState = this.gameState.turnState === 'X' ? 'O' : 'X';
            this.gameState.totalMoves++;
        }
        // END HERE

        console.log("this.gameState.totalMoves ==> " + this.gameState.totalMoves);

        var result = this.checkWinner();

        if(result === 'X') {
            this.gameState.gameEnded = true;
            this.setState({
                winner: 'X',
                winnerLine: 'X wins'
            });
            console.log("X wins");
        } else if(result === 'O') {
            this.gameState.gameEnded = true;
            this.setState({
                winner: 'O',
                winnerLine: 'O wins'
            });
            console.log("O wins");
        } else if(result === "draw") {
            this.gameState.gameEnded = true;
            this.setState({
               winner: 'draw',
               winnerLine: 'match is a draw'
            });
        }
        console.log("result ==> " + result);

        if(this.gameState.turnState === 'O' && !this.gameState.gameEnded) {
            this.gameState.gameLocked = true;

            setTimeout(() => {
                do {
                    var random = Math.floor(Math.random() * 9);
                } while(this.gameState.board[random] !== '');

                this.gameState.gameLocked = false;
                console.log("reached here");
                this.clicked(document.querySelectorAll('.square')[random]);
            }, 3000)
        }
    }

    render() {
        return(
            <div id="game">
                <div id="state">{this.state.winnerLine}</div>
                <div id="head">
                    Tic Tac Toe
                </div>

                <div id="board" onClick={(e) => this.clicked(e.target)}>
                    <div className="square" data-square="0"></div>
                    <div className="square" data-square="1"></div>
                    <div className="square" data-square="2"></div>
                    <div className="square" data-square="3"></div>
                    <div className="square" data-square="4"></div>
                    <div className="square" data-square="5"></div>
                    <div className="square" data-square="6"></div>
                    <div className="square" data-square="7"></div>
                    <div className="square" data-square="8"></div>
                </div>
            </div>
        );
    }
}

const mapStateToProps = state => {
    return {
        turnValue: state.turnValue
    };

};

const mapDispatchToProps = dispatch => {
    return {
        turnValueReducerRedux: (value) => dispatch({type: actionTypes.TURN_VALUE, value})
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(Board);

Вот turnReducer.js:

import * as actionTypes from '../actions/actions';

const initialValue = {
    turnValue: 'O'
};

const turnReducer = (state = initialValue, action) => {
    switch (action.type) {
        case actionTypes.TURN_VALUE:
            console.log("turnReducer ==> " + action.value);
            return {
                ...state,
                turnValue: action.value
            };
        default:
            return state;
    }
}

export default turnReducer;

1 Ответ

0 голосов
/ 05 октября 2018

Я думаю, что подключенное диспетчерское действие (turnValueReducerRedux) не вернет то, что вы ожидаете.Он вернет полное действие ({ type: '...', value: ... }), а не только значение, что будет означать, что turnState будет неверным в следующем коде:

let turnState = this.props.turnValueReducerRedux(this.state.turn);

if(this.gameState.board[box.dataset.square] === '') {
  this.gameState.board[box.dataset.square] = turnState;

Как общая рекомендация, кажется, вы не полагаетесь на state или хранилище для рендеринга данных, что является одной из основных обязанностей Реагирует.Таким образом, вы устанавливаете значение в хранилище, отправляя действие, но никогда не обращаетесь к нему с помощью this.state.turnValue, что определяется следующим кодом:

const mapStateToProps = state => {
    return {
        turnValue: state.turnValue
    };
};

Также имейте в виду, что gameState и state сильно отличаются друг от друга, так как последний будет вызывать повторные рендеры и будет связан с магазином, тогда как первый не будет.


ОБНОВЛЕНИЕ


В соответствии с нашим обсуждением нижеВот пример, который использует другой подход: https://codesandbox.io/s/x2x773pqxz

Автоматический компьютерный игрок - сложная часть, так как это побочный эффект действия игрока-человека.Поэтому я добавил redux-thunk, чтобы определенные действия вызывали другие действия.Я поставил задержку на поворот компьютера, чтобы вы могли увидеть его в действии.

Я также разделил доску и отдельные квадраты на отдельные компоненты, оба из которых предназначены исключительно для презентации.Компонент Game и файлы redux/actions.js являются наиболее важными.

Теоретически вы можете выбрать любой размер доски и количество игроков, но CSS просто настроен на доску 3х3.

Я не реализовал логику findWinner, потому чтоэто было слишком много усилий much

Дайте мне знать, если я смогу что-то прояснить, надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...