Próbujesz React + Redux, i prawdopodobnie robię coś oczywiście głupiego, ponieważ komponent, który uruchamia akcję pobierania danych przez sieć, nie jest aktualizowany (ponownie renderowany), gdy dane jest pobierane.React + Redux: Komponent nie aktualizuje
Oto stosowne fragmenty mojego kodu:
W index.js najwyższego poziomu służące jako punkt wyjścia dla aplikacji:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reduxPromise from 'redux-promise';
import createLogger from 'redux-logger';
const logger = createLogger();
import routes from './routes';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(reduxPromise, logger)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory} routes={routes} />
</Provider>
, document.querySelector('.container'));
kontenerem najwyższego poziomu aplikacji:
import React, {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions';
import Header from '../components/header';
import Showcase from '../components/showcase';
function mapStateToProps(state) {
return {
resources: state.resources
}
}
function mapDispatchToProps(dispatch) {
return {
fetchResources:() => {
dispatch(Actions.fetchResources());
}
}
}
class App extends Component {
render() {
console.log('props in App', this.props);
return (
<div>
<Header/>
<Showcase
fetchResources={this.props.fetchResources}
resources={this.props.resources}
/>
</div>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
Składnik, który uruchamia akcję wysłania żądania danych, gdy ma zamiar się zamontować i ma pokazywać pobrane dane:
import React, {Component} from 'react';
import {connect} from 'react-redux';
class Showcase extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.fetchResources();
}
render() {
console.log('resources', this.props);
return (
<div>
This is showcase
</div>
);
}
}
export default connect(state => ({resources: state.resources}))(Showcase)
Action Twórca:
import * as types from '../constants/ActionTypes';
import axios from 'axios';
export function fetchResources() {
return {
type: types.FETCH_FIRST,
payload: axios.get('/sampledata/1.json')
}
}
redukcyjna dla działania zwrcania:
import * as types from '../constants/ActionTypes';
export default function resourcesReducer (state={}, action) {
switch (action.type) {
case types.FETCH_FIRST:
console.log('about to return', Object.assign (state, {resources: action.payload.data }))
return Object.assign (state, {resources: action.payload.data });
default:
return state
}
};
i wreszcie reduktor root:
import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';
const rootReducer = combineReducers({
navigationReducer,
resourcesReducer
});
export default rootReducer;
Tak, o to co ja obserwując. Działanie w celu żądania danych zostało pomyślnie uruchomione, żądanie zostaje wysłane, reduktor odbiera je po rozwiązaniu obietnicy i aktualizuje stan za pomocą pobranych danych. W tym momencie oczekiwałbym, że komponent najwyższego poziomu App
i komponent Showcase
wykryją, że sklep został zaktualizowany i ponownie renderowany, ale nie widzę go w konsoli.
Również jestem zdezorientowany wyjścia konsoli redux-logger
„s:
Konkretnie, jestem zaskoczony, aby zobaczyć, że state
zawiera reduktory z rootReducer - Nie wiem, czy to prawda (przykład na Redux logger Github page pokazuje stan bez reduktorów). Wydaje się również zaskakujące, że prev state
, zgłoszone przez redux-logger
, zawiera ten sam obiekt resourcesReducer
, co next state
, chociaż intuicyjnie spodziewam się, że prev state
będzie mniej lub bardziej pusty.
Czy możesz wskazać, co robię źle i jak sprawić, by komponenty React reagowały na zmiany state
?
============================================== ====
AKTUALIZACJA:
1) Zmieniono funkcję mapStateToProps
w składniku App
tak, że prawidłowo odwzorowuje reduktor stany:
function mapStateToProps(state) {
return {
resources: state.resourcesReducer
}
}
2) Nadal przechodzących na resources
dół składnik `Showcase:
render() {
console.log('props in App', this.props);
return (
<div>
<Header navigateActions={this.props.navigateActions}/>
React simple starter
<Showcase
fetchResources={this.props.fetchResources}
resources={this.props.resources}
/>
</div>
);
3) Próba wyświetlenia resources
na ekranie przez stringifying go zobaczyć, co jest faktycznie wewnątrz tego obiektu:
render() {
console.log('resources', this.props);
return (
<div>
This is showcase {JSON.stringify(this.props.resources)}
</div>
);
}
zobacz na ekranie: This is showcase {}
. Komponent nie wydaje się ponownie renderować.
Oto zrzut ekranu z konsoli, wskazujący, że rekwizyty aplikacji zostały zaktualizowane z wartościami z next state
. Mimo to, że nie powoduje składnik do ponownego renderowania:
AKTUALIZACJA PONOWNIE: A mój javascript-fu była słaba, zbyt. Nie zdawałem sobie sprawy, że powracając Object.assign (state, {resources: action.payload.data });
faktycznie mutowałem państwo i że prosta inwersja argumentów pozwoli mi osiągnąć to, co zamierzałem. Dzięki this discussion na SO dla oświecenia.
czy próbowałeś dodać klucz do obiektu reduktora root? 'const rootReducer = combineReducers ({ nawigacja: navigationReducer, zasoby: resourcesReducer });' – anoop