React + Redux: o componente não é atualizado
Experimente o React + Redux e provavelmente estou fazendo algo obviamente estúpido, porque um componente que dispara uma ação para buscar dados pela rede não é atualizado (renderizado novamente) quando os dados são buscados.
Aqui estão os bits relevantes do meu código:
O index.js de nível superior que serve como ponto de entrada para o aplicativo:
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'));
Aplicativo de contêiner de nível superior:
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 que aciona uma ação para enviar uma solicitação de dados quando ela está prestes a montar e deve mostrar os dados buscados:
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)
Criador de ações:
import * as types from '../constants/ActionTypes';
import axios from 'axios';
export function fetchResources() {
return {
type: types.FETCH_FIRST,
payload: axios.get('/sampledata/1.json')
}
}
Redutor para a ação de busca:
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 finalmente o redutor de raiz:
import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';
const rootReducer = combineReducers({
navigationReducer,
resourcesReducer
});
export default rootReducer;
Então, aqui está o que estou observando. A ação para solicitar dados é acionada com êxito, uma solicitação é enviada, o redutor a recebe quando a promessa é resolvida e atualiza o estado com os dados buscados. Neste ponto, eu esperaria que o nível superiorApp
componente e oShowcase
componente para detectar se a loja foi atualizada e para renderizar novamente, mas não o vejo no console.
Além disso, estou confuso comredux-logger
Saída do console:
Estou especificamente surpreso ao ver que ostate
contém redutores do rootReducer - não sei se está certo (um exemplo emPágina do Github do redux logger mostra um estado sem redutores). Parece também surpreendente que oprev state
conforme relatado porredux-logger
contém o mesmoresourcesReducer
objeto como onext state
, embora intuitivamente eu esperasseprev state
estar mais ou menos vazio.
Você poderia apontar o que estou fazendo de errado e como fazer com que os componentes do React respondam aostate
alterar?
====================================================
ATUALIZADA:
1) Alterou omapStateToProps
função noApp
componente para que seja mapeado corretamente para os estados do redutor:
function mapStateToProps(state) {
return {
resources: state.resourcesReducer
}
}
2) Ainda passando oresources
até o 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) Tentando exibirresources
na tela, especificando-o para ver o que realmente está dentro deste objeto:
render() {
console.log('resources', this.props);
return (
<div>
This is showcase {JSON.stringify(this.props.resources)}
</div>
);
}
Veja isso na tela:This is showcase {}
. O componente não parece ser renderizado novamente.
Aqui está a captura de tela do console mostrando que os acessórios do aplicativo foram atualizados com os valores donext state
. Ainda assim, isso não causou a nova renderização do componente:
ATUALIZADO NOVAMENTE: E meu javascript-fu também era ruim. Eu não percebi isso ao retornarObject.assign (state, {resources: action.payload.data });
Na verdade, eu estava mudando o estado, e que uma simples inversão de argumentos me permitiria alcançar o que pretendia. Graças aessa discussão no SO para a iluminação.