Реакция компонента не обновляется при окончательной отправке и обновлении состояния притока - PullRequest
3 голосов
/ 04 апреля 2019

Я довольно новичок в React и Redux, и у меня возникла проблема с тем, что мой компонент не обновляется в последней рассылке, которая обновляет хранилище с избыточностью. Я использую thunk для предварительной загрузки некоторых данных, чтобы управлять различными частями моего сайта. Я вижу, что работающий блок и обновление состояния выглядят правильно, но когда происходит успешная диспетчеризация выборки данных, компонент не видит изменений в состоянии и впоследствии не выполняет рендеринг. интересная часть состоит в том, что первая отправка, которая устанавливает флаг загрузки, видна компонентом, и он реагирует правильно. Вот мой код:

действия

import { programsConstants } from '../constants';
import axios from 'axios'

export const programsActions = {
    begin,
    success,
    error,
};

export const loadPrograms = () => dispatch => {
    dispatch(programsActions.begin());

    axios
        .get('/programs/data')
        .then((res) => {
            dispatch(programsActions.success(res.data.results));
        })
        .catch((err) => {
            dispatch(programsActions.error(err.message));
        });
};

function begin() {
    return {type:programsConstants.BEGIN};
}
function success(data) {
    return {type:programsConstants.SUCCESS, payload: data};
}
function error(message) {
    return {type:programsConstants.ERROR, payload:message};
}

редукторы

import {programsConstants} from '../constants';
import React from "react";

const initialState = {
    data: [],
    loading: false,
    error: null
};

export function programs(state = initialState, action) {
    switch (action.type) {
        case programsConstants.BEGIN:
            return fetchPrograms(state);
        case programsConstants.SUCCESS:
            return populatePrograms(state, action);
        case programsConstants.ERROR:
            return fetchError(state, action);
        case programsConstants.EXPANDED:
            return programsExpanded(state, action);
        default:
            return state
    }
}

function fetchPrograms(state = {}) {
    return { ...state, data: [], loading: true, error: null };
}

function populatePrograms(state = {}, action) {
   return { ...state, data: action.payload, loading: false, error: null };
}

function fetchError(state = {}, action) {
    return { ...state, data: [], loading: false, error: action.payload };
}

компонент

import React from "react";
import { connect } from 'react-redux';
import { Route, Switch, Redirect } from "react-router-dom";
import { Header, Footer, Sidebar } from "../../components";
import dashboardRoutes from "../../routes/dashboard.jsx";
import Loading from "../../components/Loading/Loading";
import {loadPrograms} from "../../actions/programs.actions";

class Dashboard extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    this.props.dispatch(loadPrograms());
  }

  render() {
    const { error, loading } = this.props;

    if (loading) {
      return <div><Loading loading={true} /></div>
    }
    if (error) {
      return <div style={{ color: 'red' }}>ERROR: {error}</div>
    }

    return (
      <div className="wrapper">
        <Sidebar {...this.props} routes={dashboardRoutes} />
        <div className="main-panel" ref="mainPanel">
          <Header {...this.props} />
          <Switch>
            {dashboardRoutes.map((prop, key) => {
              let Component = prop.component;
              return (
                  <Route path={prop.path} component={props => <Component {...props} />} key={key} />
              );
            })}
          </Switch>
          <Footer fluid />
        </div>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  loading: state.programs.loading,
  error: state.programs.error
});

export default connect(mapStateToProps)(Dashboard);   

Компонент должен получать обновленные реквизиты после успешной отправки и повторного рендеринга с обновленными данными. В настоящее время компонент визуализируется только при начальной отправке и корректно показывает загружаемый компонент, но не визуализируется, когда данные извлекаются и обновляются до состояния с помощью блока.

Я исследовал это в течение пары дней, и общепринятой причиной того, что компонент не получает обновление состояния, является непреднамеренная мутация состояния, а не возвращение нового состояния. Я не думаю, что я мутирую в состоянии, но, возможно, я.

Любая помощь будет высоко ценится!

Обновление 1

По запросу вот код для создания магазина и объединения редукторов

магазин

const loggerMiddleware = createLogger();
const composeEnhancers =
    typeof window === 'object' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
        }) : compose;

const enhancer = composeEnhancers(
    applyMiddleware(
        thunk,
        loggerMiddleware)
);

export const store = createStore(rootReducer, enhancer);

Редукторный комбайн:

import { combineReducers } from 'redux';
import { alert } from './alert.reducer';
import { programs } from './programs.reducer';
import { sidenav } from './sidenav.reducer';

const rootReducer = combineReducers({
  programs,
  sidenav,
  alert
});

export default rootReducer;

Ответы [ 2 ]

0 голосов
/ 06 апреля 2019

После трех дней исследований и рефакторинга я наконец выяснил проблему и заставил ее работать. Оказывается, что проблема в версии response-redux (6.0.1) была проблемой. Откатился на 5.1.1 и все заработало без нареканий. Не уверен, что что-то сломалось в 6.0.1 или я просто использовал неправильно.

0 голосов
/ 04 апреля 2019

Ожидается, что 2-й параметр будет [preloadedState] :

export const store = createStore(rootReducer, {} , enhancer);

axios.get вернуть promise, что вам нужно await для получения ваших данных:

Попробуйте это:

   export const loadPrograms = () => async (dispatch) => {
      dispatch(programsActions.begin());

      try {
        const res = await axios.get('/programs/data');
        const data = await res.data;
        console.log('data recieved', data)
        dispatch(programsActions.success(data.results));
      } catch (error) {
        dispatch(programsActions.error(error));
      }
    };


const mapStateToProps = state => ({
  loading: state.programs.loading,
  error: state.programs.error,
  data: state.programs.data,
});

Действие Call

import React from 'react';
import { connect } from 'react-redux';
import { loadPrograms } from '../../actions/programs.actions';

class Dashboard extends React.Component {
  componentDidMount() {
    // Try to call you action this way:
    this.props.loadProgramsAction(); // <== Look at this
  }
}

const mapStateToProps = state => ({
  loading: state.programs.loading,
  error: state.programs.error,
});

export default connect(
  mapStateToProps,
  {
    loadProgramsAction: loadPrograms,
  },
)(Dashboard);
...