Provare React + Redux, e probabilmente sto facendo qualcosa ovviamente stupido, perché un componente che lancia un'azione per recuperare i dati sulla rete non viene aggiornato (ri-renderizzato) quando i dati è recuperato.React + Redux: il componente non si aggiorna
Ecco i bit rilevanti del mio codice:
I index.js di alto livello che servono come punto di ingresso per l'applicazione:
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'));
contenitore di livello superiore App:
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)
Componente che attiva un'azione per inviare una richiesta di dati quando sta per essere montata e deve mostrare i dati recuperati:
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)
Azione Creatore:
import * as types from '../constants/ActionTypes';
import axios from 'axios';
export function fetchResources() {
return {
type: types.FETCH_FIRST,
payload: axios.get('/sampledata/1.json')
}
}
riduttore per l'azione prendere:
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
}
};
e, infine, il riduttore di root:
import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';
const rootReducer = combineReducers({
navigationReducer,
resourcesReducer
});
export default rootReducer;
Quindi, ecco quello che sto osservando. L'azione per richiedere i dati viene attivata correttamente, viene inviata una richiesta, il riduttore lo riceve quando la promessa viene risolta e aggiorna lo stato con i dati recuperati. A questo punto, mi aspetto che il componente di livello superiore App
e il componente Showcase
rilevi che lo store è stato aggiornato e che è stato eseguito il re-rendering, ma non lo vedo nella console.
Inoltre, sono confuso da redux-logger
s' output della console:
In particolare, sto sorpresi di vedere che il state
contiene riduttori dal rootReducer - non so se è giusto (un esempio su Redux logger Github page mostra uno stato senza riduttori). Sembra anche sorprendente che il prev state
come riportato da redux-logger
contenga lo stesso oggetto resourcesReducer
come next state
, anche se intuitivamente mi aspetterei che prev state
sia più o meno vuoto.
Potrebbe per favore indicare cosa sto facendo male e come ottenere i componenti React rispondono alle modifiche state
?
========================================= ====
aggiornamento:
1) Modificato la funzione mapStateToProps
nel componente App
modo che associa correttamente al riduttore stati:
function mapStateToProps(state) {
return {
resources: state.resourcesReducer
}
}
2) Ancora passa il resources
giù il componente `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) Cercare di visualizzare resources
sullo schermo stringifying per vedere che cosa in realtà all'interno di questo oggetto:
render() {
console.log('resources', this.props);
return (
<div>
This is showcase {JSON.stringify(this.props.resources)}
</div>
);
}
Vai a questa sullo schermo: This is showcase {}
. Il componente non sembra ri-render.
Ecco lo screenshot della console che mostra che i puntelli dell'app sono stati aggiornati con i valori dello next state
. Ancora, che non ha causato la componente di ri-renderizzare:
nuovamente aggiornato: E il mio javascript-fu era povera, troppo. Non mi rendevo conto che restituendo Object.assign (state, {resources: action.payload.data });
stavo effettivamente mutando lo stato, e che una semplice inversione di argomenti mi avrebbe permesso di ottenere ciò che volevo. Grazie a this discussion su SO per l'illuminazione.
hai provato ad aggiungere la chiave all'oggetto riduttore radice? 'const rootReducer = combineReducers ({ navigation: navigationReducer, resources: resourcesReducer });' – anoop