Реагировать на состояние Redux Mapping, чтобы реквизит не работал - PullRequest
0 голосов
/ 09 сентября 2018

Итак, я пытаюсь изучить React с Redux и до сих пор думаю, что смог обработать большую часть кода, необходимого для его работы, но у меня возникла проблема с передачей моего состояния моему составная часть. Я использую шаблон проекта ASP.NET Core в Visual Studio 2017, который имеет реагирующий и редукционный шаблонные коды, и они использовали это:

export default connect(
  state => state.weatherForecasts,
  dispatch => bindActionCreators(actionCreators, dispatch)
)(FetchData);

Я пытался сделать то же самое с моим собственным компонентом, вот так:

export default connect(
  state => state.lecture,
  dispatch => bindActionCreators(actionCreators, dispatch)
)(LectureTable);

но при попытке доступа к содержимому моих реквизитов свойства, которые я хочу получить, помечаются как неопределенные. Я проверил через Redux devtools, что мое начальное состояние существует, но мой компонент не может видеть реквизиты, которые я пытаюсь передать ему. Странно то, что я просто имитировал шаблонный код, но он не работает, но шаблонный код работает просто отлично (то есть я могу перейти к компоненту и выйти из его исходного состояния).

Поскольку я использую формат, используемый Visual Studio, мои создатели действий, редукторы и константы находятся в одном файле, показанном ниже:

const GET_LECTURES = "GET_LECTURES";

const initialState = {
    lectures: [],
    selectedLecture: {},
    isLoading: false,
    test: 0
};

export const actionCreators = {
    requestLectures: isLoading => async (dispatch) => 
    {    
      if (!isLoading) {
        // Don't issue a duplicate request (we already have or are loading the requested data)
        return;
      }

      dispatch({ type: GET_LECTURES });

      const url = `api/lecture/`;
      const response = await fetch(url);
      const lectures = await response.json();

      dispatch({ type: RECEIVE_LECTURES, payload: lectures });
    } 
  };

export const reducer = (state = initialState, action) => {
    switch (action.type) {
    case GET_LECTURES:
        return { ...state, isLoading: true }; 
        default:
        return state;
    }
};

Извините, если все в порядке. Я действительно только начинаю понимать, что такое излишество ..

Редактировать Код моего компонента:

import React, { Component } from 'react';
import {Button, Table, Label, Menu, Icon} from 'semantic-ui-react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {actionCreators} from './../../store/Lecture';

export class LectureTable extends Component {

  componentWillMount(){
   // this.props.requestLectures(this.props.isLoading);
    console.log(this.props.test);
  }

  render() {
    return (
        <Table size='large'>
        {/*removed to make it cleaner..currently only has static data too lol*/}
      </Table>
    )
  }
}



export default connect(
  state => state.lecture,
  dispatch => bindActionCreators(actionCreators, dispatch)
)(LectureTable);

где настроен мой магазин:

import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import * as Lecture from './Lecture';
import * as Counter from './Counter';
import * as WeatherForecasts from './WeatherForecasts';

export default function configureStore(history, initialState) {
  const reducers = {
    lecture: Lecture.reducer,
    counter: Counter.reducer,
    weatherForecasts: WeatherForecasts.reducer
  };

  const middleware = [
    thunk,
    routerMiddleware(history)
  ];

  // In development, use the browser's Redux dev tools extension if installed
  const enhancers = [];
  const isDevelopment = process.env.NODE_ENV === 'development';
  if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) {
    enhancers.push(window.devToolsExtension());
  }

  const rootReducer = combineReducers({
    ...reducers,
    routing: routerReducer
  });

  return createStore(
    rootReducer,
    initialState,
    compose(applyMiddleware(...middleware), ...enhancers)
  );
}

my index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { createBrowserHistory } from 'history';
import configureStore from './store/configureStore';
import App from './pages/App';
import registerServiceWorker from './registerServiceWorker';

// Create browser history to use in the Redux store
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
const history = createBrowserHistory({ basename: baseUrl });

// Get the application-wide store instance, prepopulating with state from the server where available.
const initialState = window.initialReduxState;
const store = configureStore(history, initialState);

const rootElement = document.getElementById('root');

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <App />
    </ConnectedRouter>
  </Provider>,
  rootElement);

registerServiceWorker();

Ответы [ 6 ]

0 голосов
/ 10 сентября 2018

Я нашел решение. Прежде всего, я новичок и в стеке, и в реакции, поэтому я прошу прощения за все мои несоответствия (если это правильный термин?).

Что я узнал:

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

Некоторые примечания:

  • state => state.lecture все еще работает
  • Я приму все ваши советы близко к сердцу и соответствующим образом изменю свой код
  • Единственная причина, по которой я был непреклонен в решении проблемы с использованием кода, который у меня был, заключалась в том, что я не мог принять тот факт, что стандартный код не будет работать, если я не сделаю что-то определенно отличное от того, что сделал этот шаблон. Я просто не учел, что роутер сыграл с ним огромную роль.
  • Я повторяю ... Я реактивный новичок, так что я извиняюсь за трату вашего времени T_T

Редактировать еще раз: Мне удалось подключить другой дочерний компонент к хранилищу Redux. Я пытаюсь понять, почему я до сих пор не могу сделать это для того конкретного компонента, который заставил меня задать этот вопрос. Я обновлю свой ответ, как только найду причину.

0 голосов
/ 09 сентября 2018

У вас есть две проблемы здесь.

Вы определяете mapStateToProps функцию как первый аргумент для connect неправильно. Как многие из ответов объясняют это сейчас, вы должны использовать это так:

export default connect(
  state => ( { lecture: state.lecture } ),
  dispatch => bindActionCreators(actionCreators, dispatch)
)(LectureTable);

Теперь у вас есть lecture опора в качестве вашего состояния. Вы можете достичь этого с this.props.lecture. Но в вашем методе componentWillMount вы пытаетесь записать его как this.props.test. Это должно быть this.props.lecture.test.

Кстати, попробуйте использовать componentDidMount вместо componentWillMount, поскольку в будущих версиях он будет устаревшим.

0 голосов
/ 09 сентября 2018

Я думаю, что, выполнив следующие шаги, вы сможете решить проблему:

  1. Сначала вам нужно вызвать две функции, когда вы хотите подключить ваш компонент к состоянию приложения, одну - mapDispatchToProps, а другую - mapStateToProps, чтобы ваш код был чистым, лучше определить эти функции отдельно, а затем передать их по имени для подключения, но если вы хотите использовать свой собственный путь, вы должны внести следующие изменения: (при условии, что ваше имя редуктора является лекцией из вашего combReducers, и при условии, что вы вызываете requestLectures с этим синтаксисом: this.props.lectureActions.requestLectures ( ) и импортирование лекционных действий из файла, в котором вы написали действия, связанные с лекцией):

    export default connect(
    state => state.lecture.lectures,
    dispatch => {lectureActions: bindActionCreators(lectureActions, dispatch)}
    )(LectureTable);
    
  2. из приведенного выше кода, вам не нужно экспортировать объект, который содержит действия, такие как actionCreators, вы должны экспортировать функцию requestLectures из него независимо

  3. добавьте нижний регистр к вашему редуктору, чтобы при успешном получении лекций состояние приложения обновлялось вместе с лекциями:

    case RECEIVE_LECTURES:
      return { ...state, isLoading: false, lectures: payload.lectures }; 
      default:
      return state;
     }
    
0 голосов
/ 09 сентября 2018

Рик, ваш аргумент подключения должен выглядеть примерно так:

export default connect( state => {
    return {
      test: state.lecture // Or any value
    }
})(LectureTable);

Вы пытаетесь консоль записать в журнал команду test, поэтому вы должны включить ее в свой вызов подключения.

0 голосов
/ 09 сентября 2018

Я думаю, что в их примере weatherForecasts - это объект.В вашем примере lectures выглядит как массив, поэтому я предлагаю переписать вашу функцию mapStateToProps следующим образом, если вам нужно получить lectures prop

state => ({ lectures: state.lectures})

, если вам нужно все state у вас может быть state => state, чтобы вы могли получить доступ к реквизитам this.props.test и this.props.lectures

Имейте в виду, что mapStateToProps должен возвращать object, а не array.Кстати, в вашем редукторе имя поля равно lectures (множественное число), а не lecture, поэтому state => state.lecture будет undefined

0 голосов
/ 09 сентября 2018

Первый аргумент connect () должен быть функцией, которая возвращает объект - с реквизитами, которые вы хотите добавить в качестве ключей, а их значением является значение из состояния. например,

state => ({ lecture: state.lecture })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...