Свойство React / Redux props магазина не определено - PullRequest
0 голосов
/ 30 июня 2018

В моем приложении я использую:

"devDependencies": {
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-es2016": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "bootstrap": "^4.0.0",
    "browser-sync": "^2.24.5",
    "browser-sync-webpack-plugin": "^2.2.2",
    "cross-env": "^5.1",
    "jquery": "^3.2",
    "laravel-mix": "^2.0",
    "popper.js": "^1.12",
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-redux": "^5.0.7",
    "react-router-dom": "^4.3.1",
    "redux": "^4.0.0",
    "redux-thunk": "^2.3.0",
    "uuid": "^3.3.2"
},

На стороне притока у меня есть такая настройка: store.js:

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';

import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];

const store = createStore(rootReducer, initialState, applyMiddleware(...middleware));

export default store;

rootReducer:

import {combineReducers} from 'redux';

import menuReducer from './menuReducer';

const rootReducer = combineReducers({
  menu: menuReducer
});

export default rootReducer;

Который имеет только menuReducer в своем распоряжении:

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

const initialState = {
  data: {}
}

export default function(state = initialState, action) {
  switch (action.type) {
    case types.GET_MENU:
      return {
        ...state,
        data: action.payload
      }
    default:
      return state;
  }
}

Который получает его из одного действия меню:

import * as types from './types';

export const getMenu = () => (dispatch) => {
  fetch('/admin/json/menu.json')
  .then(res => res.json())
  .then(data => dispatch({
      type: types.GET_MENU,
      payload: data
    })
  )
}

И, наконец, на стороне компонентов у меня есть: App.js:

import React from 'react';
import {Provider} from 'react-redux';
import {BrowserRouter} from 'react-router-dom';

import store from '../store';
import SideMenu from './sidemenu';
import Content from './content';

class App extends React.Component {
  render() {
    return(
      <Provider store={store}>
        <BrowserRouter basename='/yonetim'>
          <div className="h-100">
            <SideMenu className="h-100"/>
            <Content className="h-100"/>
          </div>
        </BrowserRouter>
      </Provider>
    );
  };
};

export default App;

И компонент, который пытается использовать эту базовую реализацию редукции:

import React, {Fragment} from 'react';
import {v1 as uuid} from 'uuid';
import {connect} from 'react-redux';

import {getMenu} from '../actions/menuActions';
import MenuDropdown from './parts/menu-dropdown';
import MenuItem from './parts/menu-item';

class SideMenu extends React.Component {
  componentWillMount() {
    this.props.getMenu();
  }
  render() {
    console.log(this.props.menuData);
    return(
      <header>
        <div className="cnt-menu-head">
          <h6>{this.props.menuData.heading}</h6>
        </div>
        <div className="cnt-menu">
          <ul className="nav nav-pills flex-column">
            {this.props.menuData.sections.map((section, i) => {
              if (section.type === 'link') {
                let key = uuid();
                return <MenuItem key={key} exact={section.exact} linkTo={section.linkTo} linkText={section.linkText}/>
              } else if (section.type === 'dropdown') {
                let keyedLinks = section.links.map((link) => {
                  link.key = uuid();
                  return link;
                });
                return (
                  <Fragment key={uuid()}>
                    <div className="horizontal-separator"></div>
                    <MenuDropdown linkText={section.linkText} links={keyedLinks}/>
                  </Fragment>
                )
              }
            })}
          </ul>
        </div>
      </header>
    );
  };
};

function mapStateToProps(state) {
  return {
    menuData: state.menu.data
  }
}

export default connect(mapStateToProps, {getMenu})(SideMenu);

Что происходит:

Я получаю ошибку:

Uncaught TypeError: Невозможно прочитать свойство 'map' из неопределенного

ссылаясь на this.props.menuData.sections.map() часть моего кода. Теперь самое смешное:

  1. Функция рендеринга этого компонента вызывается дважды
  2. Когда я добавляю console.log() как в действие, так и в редуктор, я вижу, что их также вызывают дважды.
  3. Когда я закомментирую коды, которые пытаются использовать this.props.menuData в render(), тогда console.log(this.props.menuData); в начале функции рендеринга печатает пусто при первом запуске render(), а затем заполняется фактическими данными, которые я ' Я пытаюсь использовать со вторым прогоном. Я абсолютно не знаю, что происходит с этим кодом или что может быть основной причиной. Буду признателен за любую оказанную помощь. Спасибо.

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Проблема здесь в том, что вы вызываете «асинхронное» действие (выборка), которое отправляет данные после выборки.

Итак, ваш компонент загружается, но затем, когда ваша функция (getMenu) отправляет действие в Redux, ваш компонент запускается во второй раз.

Я могу предложить сделать троицу, которая обуславливает визуализацию потребителя menuData и показать загрузчик:

Внутри вашего рендера:

return this.props.menuData.sections ? (actualCodeGoesHere) : <Loader />
0 голосов
/ 30 июня 2018

Конечно, у вас нет данных при первом отображении. Есть два способа исправить это: 1. поместите ключ разделов в initialState для меню Reducer. 2. добавить обнаружение перед this.props.menuData.sections.map (…). может быть так: this.props.menuData.sections && this.props.menuData.sections.map (…)

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