2016-03-15 18 views
8

Ausprobieren React + Redux, und wahrscheinlich mache ich etwas offensichtlich dumm, weil eine Komponente, die eine Aktion zum Abrufen von Daten über das Netzwerk abfeuert nicht aktualisiert (neu gerendert) wird wird geholt.React + Redux: Komponente wird nicht aktualisiert

Hier sind die entsprechenden Bits von meinem Code:

Die Top-Level-index.js als Einstiegspunkt für die Anwendung dienen:

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')); 

Top-Level-Container 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) 

Komponente, die eine Aktion auslöst, um eine Anforderung für Daten zu senden, wenn sie bereitgestellt wird und die abgerufenen Daten anzeigen soll:

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) 

Aktion Urheber:

import * as types from '../constants/ActionTypes'; 
import axios from 'axios'; 

export function fetchResources() { 
    return { 
    type: types.FETCH_FIRST, 
    payload: axios.get('/sampledata/1.json') 
    } 
} 

Reducer für die Aktion holen:

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 
    } 
}; 

und schließlich die Wurzel Minderer:

import { combineReducers } from 'redux'; 
import navigationReducer from './navigation-reducer'; 
import resourcesReducer from './resources-reducer'; 

const rootReducer = combineReducers({ 
    navigationReducer, 
    resourcesReducer 
}); 

export default rootReducer; 

So, hier ist das, was ich beobachtet werde. Die Aktion zum Anfordern von Daten wird erfolgreich ausgelöst, eine Anforderung wird gesendet, der Reduzierer empfängt sie, wenn das Versprechen aufgelöst wird, und aktualisiert den Status mit den abgerufenen Daten. An dieser Stelle würde ich erwarten, dass die Komponente App der obersten Ebene und die Komponente Showcase erkennen, dass der Speicher aktualisiert und erneut gerendert wurde, aber ich sehe ihn nicht in der Konsole.

Auch ich bin von redux-logger ‚s Konsolenausgabe verwirrt:

enter image description here

Insbesondere bin überrascht bin, um zu sehen, dass die state Reduzierungen von der rootReducer enthält - ich weiß nicht, ob es richtig ist (Ein Beispiel auf Redux logger Github page zeigt einen Zustand ohne Reduzierungen). Es scheint auch überraschend, dass die prev state, wie von redux-logger berichtet, enthält resourcesReducer Objekt als next state, obwohl ich intuitiv erwarten würde prev state mehr oder weniger leer.

Könnten Sie bitte darauf hinweisen, was ich falsch mache und wie reagiert React Komponenten auf die state Änderungen reagieren?

============================================== ====

AKTUALISIERT:

1) Changed die mapStateToProps Funktion in der App Komponente, so dass es richtig Staaten abbildet Minderer:

function mapStateToProps(state) { 
    return { 
    resources: state.resourcesReducer 
    } 
} 

2) immer noch die resources vorbei nach unten zu die `Showcase-Komponente:

3) Der Versuch, resources auf dem Bildschirm anzuzeigen, indem es stringifying, um zu sehen, was in diesem Objekt tatsächlich ist:

render() { 
    console.log('resources', this.props); 
    return (
     <div> 
     This is showcase {JSON.stringify(this.props.resources)} 
     </div> 
    ); 
    } 

dies auf dem Bildschirm zu sehen: This is showcase {}. Die Komponente scheint nicht neu zu rendern.

Hier ist der Screenshot der Konsole, der zeigt, dass App-Requisiten mit den Werten von next state aktualisiert wurden. AKTUALISIERT

enter image description here

WIEDER: Trotzdem, dass die Komponente neu machen nicht die Ursache Und mein Javascript-fu war schlecht, auch. Ich war mir nicht ganz bewusst, dass ich durch die Rückkehr von Object.assign (state, {resources: action.payload.data }); tatsächlich den Staat mutierte, und dass eine einfache Umkehrung von Argumenten mich das erreichen ließ, was ich beabsichtigte. Danke an this discussion an SO für Aufklärung.

+0

Haben Sie versucht, einen Schlüssel zum Root Reducer-Objekt hinzuzufügen? 'const rootReducer = combineReducers ({ navigation: navigationReducer, resources: resourcesReducer });' – anoop

Antwort

6

Ich bin zu sehen surprized, dass der Staat Reduzierungen von der rootReducer

Dieses enthält, ist, wie es funktioniert. Sehen Sie sich combineReducers() genauer an.

const rootReducer = combineReducers({ 
    navigationReducer, 
    resourcesReducer 
}); 

Erkennen, dass es sich nicht um eine Liste von Parametern handelt; es ist ein einzelner Objektparameter. Vielleicht ist es klarer in ES5 Syntax:

var rootReducer = combineReducers({ 
    navigationReducer: navigationReducer, 
    resourcesReducer: resourcesReducer 
}); 

resourcesReducer Die Schlüsselpunkte auf den Zustand durch die resourcesReducer() Funktion zurückgegeben. Das heißt, die state Variable innerhalb der resourcesReducer() ist nur ein Teil des gesamten Staates.

Die Funktionen übergeben an connect() nehmen den gesamten Zustand als ein Argument. Wie sollte Ihr Gerät aussehen?

export default connect(state => ({ 
    resources: state.resourcesReducer.resources 
}))(Showcase); 
+0

Vielen Dank. Ihr Kommentar hat deutlich gemacht, was die Beziehungen zwischen dem Staat und den Reducern (und den combinedReducern) sind, aber selbst nachdem ich meinen Code aktualisiert habe (siehe den AKTUALISIERTEN Abschnitt meiner ursprünglichen Frage), führt eine Aktualisierung des Status nicht zu einer Neugestaltung der Komponente . Ich abonniere jetzt nur meine App-Komponente für den Store und habe die Funktion "mapStateToProps" so geändert, dass "{resources: state.resourcesReducer}" zurückgegeben wird.Ich sehe, dass der Status aktualisiert wird und dass die Requisiten von "App" diese Änderung widerspiegeln, aber dies führt nicht dazu, dass die App (oder der Showcase) erneut rendert. Was vermisse ich? – azangru

+1

Ok, jetzt verstehe ich, was passiert ist. Mein 'Object.assign' war auch falsch. Ich mutierte den Zustand: 'return Object.assign (state, {resources: action.payload.data})' während das, was ich wirklich tun musste, war ein neues Objekt (zB 'return Object.assign ({resources: action .payload.data}, state) '). Wie dumm von mir. Scheint jedoch ein häufiger Fehler zu sein; Es gibt einen sehr ähnlichen Beitrag zu SO, den ich vermisst habe: http://stackoverflow.com/questions/33140008/react-redux-store-updates-but-react-does-not – azangru

Verwandte Themen