简体   繁体   中英

React + redux, component fetches data via redux-thunk and subscribes to it but the props doesn't update when they change

In my app componentDidMount I make a simple call to redux. the data gets fetched via an api and set to the store. When logging the data from the reducer it's all there but for some reason my App component doesn't update even though the props should get changed.

Kinda clueless what I am missing here, any help would be appreciated.

App.js:

import React, { Component } from "react";

import { library } from "@fortawesome/fontawesome-svg-core";
import { faIgloo, faBars, faUser } from "@fortawesome/free-solid-svg-icons";
import { initializeIcons } from "@uifabric/icons";
import { acquireToken, acquireGraphToken } from "../../adalConfig";

import Navbar from "../../common/navbar/navbar";
import Searchbar from "../../common/utils/searchBar/searchBar";
import LeftNavigation from "../../common/leftNavigation/leftNavigation";
import PageContainer from "../pageContainer/pageContainer";
import { IntlProvider } from "react-intl";

import WithLoading from "../../common/utils/withLoading";

import messages_en from "../../assets/translations/translations_en";
import messages_nl from "../../assets/translations/translations_nl";
import StylesheetLoader from "../../common/utils/stylesheetLoader/stylesheetLoader";
import ReactAI from "react-appinsights";
import { connect } from "react-redux";
import * as userActions from "../../store/users/actions";
import * as tokenActions from "../../store/tokens/actions";

initializeIcons();
library.add(faIgloo, faBars, faUser);

class App extends Component {
    state = {
        languageChoice: "en",
        theme: "red",
        tokensAreLoaded: false,
        token: ""
    };

    componentDidMount() {
        this.props.onFetchCurrentUser();
        this.props.onFetchTokens();
        console.log("selected language", this.props);
    }

    render() {
        // Sets an interval that refreshes to get the token every 15 minutes
        // We use this because our custom API's do not automatically issue a
        // refresh token.

        setInterval(AppTokenRefresher, 900000);

        function AppTokenRefresher() {
            acquireToken();
            acquireGraphToken();
        }

        let loader = "";

        if (this.props.currentUserLoading) {
            loader = <WithLoading isLoading={true} />;
        }

        const messages = {
            nl: messages_nl,
            en: messages_en
        };

        ReactAI.setAppContext({ urlReferrer: document.referrer });
        // const Ai = ReactAI.ai();

        // function test() {
        //   Ai.trackEvent('Testing', { 'user': 'me' });
        // }

        return (
            <React.Fragment>
                {this.props.currentUser.name}
                {loader == "" ? (
                    <React.Fragment>
                        <StylesheetLoader />
                        <IntlProvider
                            locale={this.state.languageChoice}
                            messages={messages[this.state.languageChoice]}
                        >
                            <div className="siteContainer">
                                <Navbar currentUserProfile={this.props.currentUser} />

                                <div className="mobile-searchbar">
                                    <Searchbar />
                                </div>

                                <div className="page-container">
                                    <aside>
                                        <LeftNavigation />
                                    </aside>

                                    <section className="main">
                                        <PageContainer />
                                    </section>
                                </div>
                            </div>
                        </IntlProvider>
                    </React.Fragment>
                ) : (
                    <div>{loader}</div>
                )}
            </React.Fragment>
        );
    }
}

const mapStateToProps = state => {
    return {
        currentUserError: state.currentUserSlice.currentUserError,
        currentUserLoading: state.currentUserSlice.currentUserLoading,
        currentUser: state.currentUserSlice.currentUser,
        tokensAreLoaded: state.tokensSplice.tokensAreLoaded
    };
};

const mapDispatchToProps = dispatch => {
    return {
        onFetchCurrentUser: () => dispatch(userActions.fetchCurrentUser()),
        onFetchTokens: () => dispatch(tokenActions.fetchRequest())
    };
};

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App);

Actions.js

import { adalOneApiFetch } from "../../adalConfig";
export const FETCH_CURRENT_USER = "FETCH_CURRENT_USER";
export const FETCH_CURRENT_USER_STARTED = "GET_CURRENT_USER_STARTED";
export const FETCH_CURRENT_USER_SUCCESS = "FETCH_CURRENT_USER_SUCCESS";
export const FETCH_CURRENT_USER_FAILURE = "FETCH_CURRENT_USER_FAILURE";

export const fetchRequest = () => {
    return (dispatch, getState) => {
        const currentState = getState();

        dispatch(fetchCurrentUserStarted());

        adalOneApiFetch(
            fetch,
            "https://one365-api-dev.azurewebsites.net/api/me",
            {}
        )
            .then(response => {
                // If the reponse code is not positive, throw an error.
                if (response.status != 200 && response.status != 204) {
                    dispatch(fetchCurrentUserFailure("fout"));
                    return;
                }

                response.json().then(result => {
                    dispatch(fetchCurrentUserSuccess(result));
                });
            })
            .catch(error => {
                dispatch(fetchCurrentUserFailure(error));
            });
    };
};

export const fetchCurrentUserSuccess = users => {
    return {
        type: FETCH_CURRENT_USER_SUCCESS,
        payload: {
            ...users
        }
    };
};

export const fetchCurrentUserStarted = () => ({
    type: FETCH_CURRENT_USER_STARTED
});

export const fetchCurrentUserFailure = error => {
    return {
        type: FETCH_CURRENT_USER_FAILURE,
        payload: {
            error
        }
    };
};

export const fetchCurrentUser = () => {
    return dispatch => {
        dispatch(fetchRequest());
    };
};

reducer.js:

import * as actions from "./actions";

const initialState = {
    currentUserError: "",
    currentUserLoading: false,
    currentUser: []
};

const currentUserReducer = (state = initialState, action) => {
    switch (action.type) {
        case actions.FETCH_CURRENT_USER_STARTED: {
            return {
                ...state,
                loading: (state.currentUserLoading = true)
            };
        }

        case actions.FETCH_CURRENT_USER_SUCCESS: {
            console.log("current user from reducer", action);

            return {
                ...state,
                currentUserLoading: false,
                currentUser: action.payload
            };
        }

        case actions.FETCH_CURRENT_USER_FAILURE: {
            return {
                ...state,
                currentUserLoading: false,
                currentUserError: action.payload.error.message
            };
        }

        default: {
            return state;
        }
    }
};

export default currentUserReducer;

Screenshot of rendering cycle: 在此输入图像描述

在此输入图像描述

You are accessing the wrong data in

const mapStateToProps = state => {
    return {
        currentUserError: state.currentUserSlice.currentUserError,
        currentUserLoading: state.currentUserSlice.currentUserLoading,
        currentUser: state.currentUserSlice.currentUser,
        tokensAreLoaded: state.tokensSplice.tokensAreLoaded
    };
};

Your reducer name is currentUserReducer so your mapStateToProps should be like this.

const mapStateToProps = state => {
    return {
        currentUser: state.currentUserReducer.currentUser,
    };
};

It actually turned out that redux was working well. But I was logging the data in componentDidMount which means only once the component is mounted the first time... changed it to the willupdate method and things were working fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM