2016-12-19 6 views
0

Я изучаю реакцию и редукцию, и столкнулся с ошибкой, в которой я не могу найти исправление. Функция mapStateToProps получает начальное (и пустое) состояние. Я использую бесшовные-Неизменяемые для объекта state, и я знаю, что мой редуктор фактически вызывается и обновляет состояние. Я попытался каждый компонент-реквизит связанных метод (componentWillReceiveProps, componentWillMount, componentDidMount и т.д ..), и mapStateToProps никогда не получает состояние обновленных; всегда начальное пустое состояние. он запускается до того, как this.props.dispatch может быть вызван в рамках этих методов.Как mapStateToProps получает обновленное состояние в реализации react-redux

Я должен что-то не хватает ...

соответствующие файлы:

1. приложение/index.js

import React, { Component } from 'react'; 
import logo from './logo.svg'; 
import './index.css'; 
import PlaylistList from '../../components/PlaylistList'; 
import { fetchPlaylists } from '../../store/playlists/actions'; 
import { getPlaylists } from '../../store/playlists/reducer'; 
import { connect } from 'react-redux'; 

class App extends Component { 
    componentWillReceiveProps() { 
    this.props.dispatch(fetchPlaylists(); 
    } 
    render() { 
    return (
     <div className="App"> 
     <div className="App-header"> 
      <img src={logo} className="App-logo" alt="logo" /> 
      <h2>Welcome to My Music Store</h2> 
     </div> 
     <PlaylistList playlists={this.props.playlists}></PlaylistList> 
     </div> 
    ); 
    } 
} 

function mapStateToProps(state) { 
    console.dir(state); // prints the initial state (before reducer run) 
    return {playlists: getPlaylists(state)} 
} 

export default connect(mapStateToProps)(App); 

2. actions.js:

import * as api from '../../services/api'; 
import * as types from './actionTypes'; 
import _keyBy from 'lodash/keyBy'; 

export function fetchPlaylists() { 
    return async (dispatch, getState) => { 
    try{ 
     const playlists = await api.fetchPlaylists(); 
     const playlistsById = _keyBy(playlists, (playlist) => playlist.id); 
     dispatch({ type: types.PLAYLISTS_FETCHED, playlistsById}); 
    } catch (error) { 
     console.error(error); 
    } 
    } 
} 

3. reducer.js:

import * as types from './actionTypes'; 
import _mapKeys from 'lodash/mapKeys'; 
import _mapValues from 'lodash/mapValues'; 
import Immutable from 'seamless-immutable'; 

const initialState = Immutable({ 
    playlistsById: {}, 
    currentPlaylist: undefined 
    } 
); 

export default function reduce(state = initialState, action = {}){ 
    switch (action.type) { 
    case types.PLAYLISTS_FETCHED: 
     return state.merge({ 
     playlistsById: action.playlistsById 
     }) 
    default: return state 

    } 
} 

export function getPlaylists(state) { 
    let playlistsById = state.playlistsById; 
    let playlistIds = _mapKeys(state.playlistsById); 
    console.dir({playlistsById, playlistIds}); // prints empty objects 
} 

4. reducers.js:

import playlistsReducer from './playlists/reducer'; 

export { playlistsReducer }; 

5. actionTypes.js

export const PLAYLISTS_FETCHED = 'playlists.PLAYLISTS_FETCHED'; 
export const PLAYLIST_ADDED = 'playlists.PLAYLIST_ADDED'; 
export const PLAYLIST_REMOVED = 'playlists.PLAYLIST_REMOVED'; 
export const PLAYLIST_UPDATED = 'playlists.PLAYLIST_UPDATED'; 
export const FILTER_BY_SEARCH = 'playlists.FILTER_BY_SEARCH'; 

6. src/index.js

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { createStore, applyMiddleware, combineReducers } from 'redux'; 
import { Provider } from 'react-redux'; 
import thunk from 'redux-thunk'; 
import App from './containers/App'; 
import './index.css'; 
import * as reducers from './store/reducers'; 

const store = createStore(combineReducers(reducers), applyMiddleware(thunk)); 

ReactDOM.render(
    <Provider store={store}> 
     <App /> 
    </Provider>, 
    document.getElementById('root') 
); 

ответ

1

Проблема с реализацией в том, что в mapStateToProps вы ожидаете state аргумент для обозначения состояния вашего playlistsReducer, в то время как на самом деле это относится ко всему состояния объекта со всеми своими редукторами сложенных combineReducers функции.

Правильный путь к playlistsReducer в штате будет - state.playlistsReducer. В результате, ваш mapStateToProps должен выглядеть следующим образом:

function mapStateToProps(state) { 
    console.dir(state.playlistsReducer); // prints the initial state (before reducer run) 
    return {playlists: getPlaylists(state.playlistsReducer)} 
} 

Используя этот mapStateToProps, getPlaylists получит нужный объект с нужными данными, чтобы передать необходимые реквизиты для компонента.

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

+0

ну, я изменил его на 'state.playlistsReducer', но ничего хорошего. все еще не содержит данных ... –

+0

Если вы говорите, что состояние обновляется, когда действие отправляется, а mapStateToProps не вызывается после него, это кажется очень странным. Не могли бы вы поместить этот код на какую-нибудь площадку разработчика, например codepen.io, чтобы я мог поиграть с ней? –

+0

https: // github.com/zukoaang/react-redux-реализация –