2016-07-28 11 views
2

Ich habe eine React-Komponente, die mit Redux-Speicher verbunden ist. Ich hole Ressourcen (Beiträge) in der componentWillMount Life-Cycle-Methode.Async-Aktion mit Redux

componentWillMount() { 
    this.props.fetchPosts(); 
} 

Die Komponente wird zu Redux Store abonnieren und isFetching und posts aus dem Laden zu bekommen.

const mapStateToProps = (state) => { 
    return { 
    posts: getAllPosts(state), 
    isFetching: getIsFetchingPosts(state), 
    } 
} 

Ich mag einen Spinner zeigen, wenn es nach wie vor ist das Abrufen, so in der render Methode würde Ich mag, dies zu tun.

render() { 
    if (this.props.isFetching) { 
    return <Spinner /> 
    } 

    return this.props.posts.map(post => <PostItem key={post.id}{...post}/>) 
} 

aber wenn ich isFetching in dem Verfahren render console.log zunächst zeigt es false und dann true und dann schließlich false.

Im Idealfall, wenn dieser Container zum ersten Mal rendert isFetching Zustand ist bereits auf true festgelegt und zeigt den Spinner. Welche Änderungen muss ich vornehmen, um dies zu ermöglichen?

Hier ist der Code für die Aktion Schöpfer und Reduzierungen

/*** Action Creator ***/ 
export const fetchPosts =() => (dispatch) => { 
    dispatch({ 
    type: REQUEST_POSTS, 
    }); 

    return axios({ 
    method: 'get', 
    url: `${API_URL}/posts`, 
    }) 
    .then(({data}) => { 
    dispatch({ 
     type: RECEIVE_POSTS, 
     payload: data.posts, 
    }) 
    }) 
    .catch((response) => { 
    // some error handling. 
    }); 
} 


/*** Reducers ***/ 
const initialState = { 
    isFetching: false, 
    allIds: [], 
    byId: {}, 
}; 

const isFetching = (state = initialState.isFetcthing, action) => { 
    switch (action.type) { 
    case REQUEST_POSTS: 
     return true; 
    case RECEIVE_POSTS: 
     return false; 
    default: 
     return state; 
    } 
} 

const allIds = (state = initialState.allIds, action) => { 
    switch (action.type) { 
    case RECEIVE_POSTS: 
     return action.payload.map(post => post.id); 
    default: 
     return state; 
    } 
} 

const byId = (state = initialState.byId, action) => { 
    switch (action.type) { 
    case RECEIVE_POSTS: 
     return action.payload.reduce((nextState, post) => { 
     nextState[post.id] = post; 
     return nextState; 
     }, {...state}); 
    default: 
     return state; 
    } 
} 

const posts = combineReducers({ 
    isFetching, 
    allIds, 
    byId, 
}); 

export default posts; 


/*** Selectors in 'posts.js' file ***/ 

export const getAllPosts = (state) => { 
    const { allId, byId } = state; 
    return allIds.map(id => byId[id]); 
} 

/*** rootReducer file ***/ 
import posts, * as fromPosts from './posts'; 


const rootReducer = combineReducers({ 
    posts, 
}) 

export default rootReducer; 

export const getAllPosts = (state) => { 
    return fromPosts.getAllPosts(state.posts); 
}; 

Vielen Dank im Voraus!

+0

nicht wirklich klar, was fetchPosts ist Sie stellen es nicht in mapStateToProps bereit. Und was sind die Verbindungen zwischen den Posts von state und fetchPosts (funktioniert die Funktion update?). Könnten Sie das klären? – berliner

+0

Wenn man 'isFetching = false 'am Anfang hat, ist das ein ok-Verhalten, da es nur bedeutet, dass die Aktion den Reducer noch nicht getroffen hat, dh' render' wurde aufgerufen, bevor 'fetchPosts' das Flag auf true gesetzt hat. – Igorsvee

Antwort

1

Die einfache Antwort ist, dass dies das erwartete Verhalten ist, angesichts Ihrer Implementierung. Sie ordnen den Status isFetching einem Prop zu. Hier ist, was passiert:

  1. Der Anfangswert von isFetching im Zustand Baum false ist, so dass der isFetching prop Wert false ist, so dass es als false macht.

  2. Sie versenden eine Aktion, die im Zustandsbaum isFetching in true ändert. Dieser neue Status wird einem neuen isFetching Prop-Wert von true zugeordnet, der ein erneutes Rendern verursacht, wobei es als true gerendert wird.

  3. Sie senden (asynchron) eine weitere Aktion, die isFetching zurück in false im Statusbaum ändert. Wie in (2) bewirkt dies ein erneutes Rendering mit isFetching als false.

Die einfache Lösung, wenn Sie einfach ein true, false von machen wollen *, mit der aktuellen Implementierung ist isFetching zu true in Ihrem Minderer des Ausgangszustand zu setzen.

Ob diese Implementierung Sinn auf Design-Ebene macht für diese Komponente eine breitere Frage ist, dass es nicht genug Kontext ist hier zu beantworten :-)

* update auf Vollständigkeit soll ich sagen, dass ich don‘ t wissen, ob die render() Funktion zweimal aufgerufen würde, mit isFetching gelöst als true,false oder dreimal mit true,true,false in diesem Fall.Ich vermute, dass react-redux das Rendern der Komponente so optimieren kann, dass kein erneutes Rendering erfolgt, wenn die gemappte true ->true, aber weiß das nicht sicher - wäre dankbar und interessiert, wenn Sie lassen könnten Ich weiß, was Ihre Logging-Ausgaben?

In jedem Fall auf dem DOM Level zwei sicherlich nur auftreten würde Renderings aufgrund des Standard reagieren virtual-DOM diffing Optimierung, so in der Tat das Ergebnis das gleiche ist oder so

+0

danke für die Antwort! Ich habe gerade die Frage aktualisiert. "Im Idealfall, wenn dieser Container zum ersten Mal rendert, ist der Status" Fetching "bereits auf" true "gesetzt und zeigt den Spinner an. Welche Änderungen muss ich vornehmen, damit dies geschieht?" Hast du Ideen dafür? Ich benutze übrigens "react-router". –

+0

Kein Problem. Um ehrlich zu sein, das ist etwas, mit dem ich in meinen eigenen Reducer-Designs zu kämpfen hatte - wie man einen Anfangszustand behält und diesen Anfangszustand für jedes neue Rendering der Komponente zurücksetzt. Sie können den Anfangszustand so einstellen, dass 'isFetching' zutrifft, und dann sicherstellen, dass dieser Wert in der Statusbaumstruktur auf" true "zurückgesetzt wird, bevor Sie diese Komponente später rendern. Dies könnte je nach Design etwas mühsam sein. Ein anderer, einfacherer Weg besteht darin, "isFetching" als internen Zustand der Komponente beizubehalten und ihn bei jedem Mounten der Komponente mit getInitialState() zurückzusetzen. – davnicwil

+0

(cont) Ich denke, dies ist eine dieser Designoptionen ohne eine klare Antwort. Es hängt nur von deiner App ab :-) Für mich, wie ich schon sagte, ist es eine der großen offenen Fragen beim Schreiben einer App mit redux, wo diese kleinen, unabhängigen UI-Zustände zu halten sind. – davnicwil