Может кто-нибудь показать мне, что не так с моим состоянием Redux?

#javascript #reactjs #redux #react-redux #mern

#javascript #reactjs #redux #реагировать-redux #мерн

Вопрос:

Редактировать

Компонент, в котором это состояние не отображается, называется TournamentShow , который вызывает состояние и любые функции, которые мне нужно использовать для отображения страницы.

Вложенный в него условный вызов одной из 3 страниц, основанный на

Tournament.Status === "Open" ,

Tournament.Status === "Closed" , и

Tournament.Status === "Complete"

Турнирное шоу:

 import React, { Component } from 'react';
import { SignUpPage, HostUI, StartBracket, Results } from './TournamentScreens';
import {
    showTournament,
    addParticipant,
    closeTournament,
    shuffleParticipants
} from '../../actions/tournamentActions';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Spinner } from 'reactstrap';

class TournamentShow extends Component {
    constructor(props) {
        super(props);
        this.onSignUp = this.onSignUp.bind(this);
        this.onStartTournament = this.onStartTournament.bind(this);
        this.onShuffleParticipants = this.onShuffleParticipants.bind(this);
    };

    componentDidMount() {
        const id = this.props.match.params.id;
        this.props.showTournament(id);
    };

    static propTypes = {
        tournament: PropTypes.object.isRequired,
        auth: PropTypes.object.isRequired
    };

    onSignUp(tournamentId, user) {
        this.props.addParticipant(tournamentId, user);
    };

    onShuffleParticipants(array) {
        let currentIndex = array.length, temporaryValue, randomIndex;   
        while(0 !== currentIndex) {
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;  
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
        }   
        return array;
    };

    onStartTournament(tourneyId) {
        const { participants } = this.props.tournament.showTournament;

        // Randomize participants
        let reorderedParticipants = [];
        const shuffledParticipants = this.onShuffleParticipants(participants);
        shuffledParticipants.forEach(participant => {
            reorderedParticipants.push(participant);
        });

        // Send new participants list to backend
        this.props.shuffleParticipants(tourneyId, reorderedParticipants);

        // Set Status to "Closed"
        this.props.closeTournament(tourneyId);
    };

    render() {
        console.log(this.props.tournament)
        const loading = this.props.tournament.loading || !this.props.tournament.showTournament;

        if(loading) {
            return <Spinner color="light" /> 
        } else {
            if(this.props.tournament.showTournament.status === "Complete") {
                return (
                    <Results />
                );
            } else if(this.props.tournament.showTournament.status === "Closed") {
                return (
                    <div>
                        <HostUI
                            tournament={this.props.tournament.showTournament}
                        />
                        <StartBracket
                            tournament={this.props.tournament.showTournament}
                        />
                    </div>
                );
            } else {
                return (
                    <SignUpPage
                        tournament={this.props.tournament.showTournament}
                        auth={this.props.auth}
                        onSignUp={this.onSignUp}
                        onStartTournament={this.onStartTournament}
                    />
                );
            }
        };
    };
};

const mapStateToProps = state => ({
    tournament: state.tournament,
    auth: state.auth
});

export default connect(mapStateToProps, 
    { showTournament, addParticipant, closeTournament, shuffleParticipants }
)(TournamentShow);
  

Экраны показа турниров:

 import React from 'react';
import moment from 'moment';
import { TournamentSignUp, StartTournament } from './resources/buttons';
import { TournamentRules } from './resources/rulesets';
import { Button } from 'reactstrap';
import { Link } from 'react-router-dom';


// Status === "Open"
export const SignUpPage = ({ tournament, auth, onSignUp, onStartTournament }) => {
};


// Status === "Closed"
export const HostUI = ({ tournament }) => {
    const { players } = tournament.bracket;

    return (
        <div style={{color:"lightgrey"}}>
            <h1>Host UI</h1>
            {
                players amp;amp; players.map(player => (
                    <div>
                        {player.username}
                    </div>
                ))
            }
        </div>
    );
};


export const StartBracket = ({ tournament }) => {
    const { title, hostedBy, participants } = tournament;

  return (
    <div className="text-center" style={{color:"lightgrey", backgroundColor: "#333333"}}>
      <h1>{ title }</h1>
      <h4>By { hostedBy }</h4>
      <h4>{participants amp;amp; participants.length}-player bracket</h4>
      <br /><Link to="/">Back to Tournaments main page</Link>
    </div>
  );
};


// Status === "Complete"
export const Results = () => {
};
  

Status===Closed показывает оба этих центральных компонента.

HostUI отображает только players массив (который только что был обновлен непосредственно перед переключением / повторным отображением состояния)

StartBracket показывает материал из ShowTournament , то есть все данные, которые уже были установлены в состоянии

ОРИГИНАЛ —————————

I’ll mark with // comment which case does not work

 import { 
    GET_TOURNAMENTS, 
    SHOW_TOURNAMENT, 
    ADD_TOURNAMENT,
    ADD_TOURNAMENT_FAIL,
    EDIT_TOURNAMENT,
    EDIT_TOURNAMENT_FAIL,
    DELETE_TOURNAMENT, 
    TOURNAMENTS_LOADING, 
    TOURNAMENT_LOADING,
    USER_JOINS_TOURNAMENT, 
    TOURNAMENT_SIGN_UP_FAIL,
    TOURNAMENT_STATUS_UPDATE,
    TOURNAMENT_STATUS_FAILED,
    SHUFFLE_PARTICIPANTS,
    SHUFFLE_FAILED
} from '../actions/types';


const initialState = {
    tournaments: [],
    showTournament: {},
    loading: false,
};

export default function(state = initialState, action) {
    switch(action.type) {
        case GET_TOURNAMENTS:
            return {
                ...state,
                tournaments: action.payload,
                loading: false
            };

        case SHOW_TOURNAMENT:
            return {
                ...state,
                showTournament: action.payload,
                loading: false
            };

        case ADD_TOURNAMENT:
            return {
                ...state,
                tournaments: [action.payload, ...state.tournaments]
            };

        case DELETE_TOURNAMENT:
            return {
                ...state,
                tournaments: state.tournaments.filter(tournament => tournament._id !== action.payload)
            };

        case TOURNAMENTS_LOADING:
        case TOURNAMENT_LOADING:
            return {
                ...state,
                loading: true
            };

        case USER_JOINS_TOURNAMENT:
            return {
                ...state,
                ...state.showTournament.participants.push(action.payload)
            };

        case TOURNAMENT_STATUS_UPDATE:      // Occurs with SHUFFLE_PARTICIPANTS, which doesn't work
            return {
                ...state,
                ...state.showTournament.status = action.payload
            };

        case SHUFFLE_PARTICIPANTS:          // Does not work
            return {
                ...state,
                ...state.showTournament.bracket.players.push(action.payload)
            }

        case EDIT_TOURNAMENT:
        case ADD_TOURNAMENT_FAIL:
        case EDIT_TOURNAMENT_FAIL:
        case TOURNAMENT_SIGN_UP_FAIL:
        case TOURNAMENT_STATUS_FAILED:
        case SHUFFLE_FAILED:
            return {
                ...state,
            }

        default:
            return state;
    };
};
  

Большая часть этого работает.
Я уверен, что я облажался TOURNAMENT_STATUS_UPDATE , и SHUFFLE_PARTICIPANTS , хотя обновление статуса работает так, как задумано.

Это турнирное приложение, на странице показа которого отображаются 3 разных компонента на основе showTournament.status

 ...

    if(loading) {
        return <Spinner color="light" /> 
    } else {
        if(this.props.tournament.showTournament.status === "Complete") {
            return (
                <Results />
            );
        } else if(this.props.tournament.showTournament.status === "Closed") {
            return (
                <div>
                    <HostUI
                        tournament={this.props.tournament.showTournament}
                    />
                    <StartBracket
                        tournament={this.props.tournament.showTournament}
                    />
                </div>
            );
        } else {
            return (
                <SignUpPage
                    tournament={this.props.tournament.showTournament}
                    auth={this.props.auth}
                    onSignUp={this.onSignUp}
                    onStartTournament={this.onStartTournament}
                />
            );
        }
    };
  

Кнопка компонента:

  • рандомизирует Tournament.participants и отправляет его в Tournament.bracket.players
  • Наборы Tournament.status === "Closed"

Это обновляет страницу и Status: "Closed" правильно отображает страницу.

Проблема в том, что он отображает только то, что я уже загрузил в состояние. (материал из SHOW_TOURNAMENT )

bracket.players Массив, в который я отправил рандомизированный список пользователей, не отображается, пока я не обновлю страницу.

Ответ №1:

Вам нужно мелко копировать каждый уровень состояния, которое вы обновляете. Кроме того, ...state.showTournament.bracket.players.push(action.payload) будет просто пытаться распространить возвращаемое значение push , которое является просто новой длиной массива. Это не то, что вы хотите.

 case TOURNAMENT_STATUS_UPDATE:
  return {
    ...state,
    showTournament: {
      ...state.showTournament,
      status: action.payload,
    },
  };

case SHUFFLE_PARTICIPANTS:
  return {
    ...state,
    showTournament: {
      ...state.showTournament,
      bracket: {
        ...state.showTournatment.bracket,
        players: [...state.showTournament.bracket.players, ...action.payload], // spread payload array
      },
    },
  }
  

Комментарии:

1. Я читал это в документах, но это не дошло. Хорошо, я только что попробовал это. То же самое. Компонент обновляется и показывает следующую страницу (в соответствии со статусом), но мне все равно нужно обновить, чтобы отобразить игроков

2. @Cin88 В каком компоненте состояние не обновляется? Можете ли вы включить этот код компонента и как он связан с вашим хранилищем redux?

3. Спасибо Дрю. Обновил сообщение, чтобы ответить на ваш вопрос

4. @Cin88 Вы убедились, что ваши действия затрагивают redux и reducer? Установлен ли у вас redux-devtools, чтобы проверить, что состояние обновлено до того, что вы ожидаете? Если вы реализуете componentDidUpdate функцию, видите ли вы там обновленные реквизиты?

5. @Cin88 Отлично! Я также внес изменения в свой ответ. Приветствия. componentDidUpdate это просто функция жизненного цикла, вызываемая при обновлении состояния или реквизита, это простое место, где можно просто удалить журнал консоли для всего, что вы хотите проверить при повторной визуализации компонента.

Ответ №2:

Решение Дрю сработало, просто для того, чтобы передать массив в другой массив, синтаксис

players: [...state.showTournament.bracket.players. ...action.payload]

вместо players: [...state.showTournament.bracket.players, action.payload]

Добрый день