Инициализация приложения

Под инициализацией приложения подразумевается включение прелоадера (анимации загрузки) до того момента, когда данные с сервера о пользователе подгрузятся. Это поможет избежать всяких “перемигиваний”.

  1. Делаем компоненту App (в App.js) классовой. И конектим в нее санку
    getAuthUserData, которая до этого у нас конектилась и запускалась из пропсов в Header.jsx.
    class App extends React.Component {
    
      componentDidMount() {
        this.props.getAuthUserData();
      }
      
      render() {
        return (
            <div className="app-wrapper">
            <HeaderContainer />
              <Navbar />
              <div className="app-wrapper-content">
                  <Route path='/dialogs' render={ () => <DialogsContainer /> } />
                  <Route path='/profile/:userId?' render={ () => <ProfileContainer /> } />
                  <Route path='/users' render={ () => <UsersContainer /> } />
                  <Route path='/news' render={ () => <News /> } />
                  <Route path='/music' render={ () => <Music /> } />
                  <Route path='/setings' render={ () => <Setings /> } />
                  <Route path='/login' render={ () => <Login /> } />
              </div>
            </div>
        );
      }
    }
    
    export default withRouter (connect(mapStateToProps, {getAuthUserData}) (App));

    Обратите внимание, что применен в последней строке не просто HOC connect, а также HOC withRouter, иначе не заработает и причину будет сложно найти.

  2. Теперь эту строку стоит записать более правильно, используя compose:
    export default compose (
     withRouter,
     connect(mapStateToProps, {getAuthUserData})) (App);
    
  3. У нас все заработало, но работает с теми же проблемами, что и раньше. Нам нужна проверка, чтобы знать, мы уже проинициализировались или не проинициализировались, только после чего загружать дальше.
    Для этого создаем app-reducer.js:

    import { getAuthUserData } from "./auth-reducer";
    
    const INITIALIZED_SUCCESS = 'INITIALIZED_SUCCESS';
    
    let initialState = {
        initialized: false
    }
    
    const appReducer = (state = initialState, action) => {
        switch(action.type) {
            case INITIALIZED_SUCCESS:
                return {
                    ...state,
                    initialized: true
                }
        default:
            return state;
        }
    }
    
    export const initializedSuccess = () => ({ type: INITIALIZED_SUCCESS}); //[1]
    
    export const initializeApp = () => (dispatch) => { //[2]
        let promise = dispatch(getAuthUserData()); // [3]
        promise.then( () => {
            dispatch(initializedSuccess()); // [4]
        }) 
    }
    
    export default appReducer;
    [1] это экшн-криэйтер и возвращаемый экшн;
    [2] это наша санка;
    [3] здесь мы и диспатчим санку с другого редьюсера, и объявляем наш промис;
    [4] здесь после полного завершения диспатча начинается диспатч нашего экшнкриэйтера.

     

  4. Но если, например, у нас перед выполнением промиса будет несколько других, то можно немного переписать код, применив Promise.all:
    export const initializeApp = () => (dispatch) => {
        let promise = dispatch(getAuthUserData());
        Promise.all([promise])
            .then( () => {
            dispatch(initializedSuccess());
        }) 
    }

    Если промисов будет больше одного, то их нужно также поместить в массив [promise].

  5. Не забываем добавить наш новый редьюсер app-reducer.js “закомбайнить” в файле, где мы “комбайним” все дедьюсеры. В нашем случае это файл redux-store.js. Назовем его при этом app:
    ...
    let reducers = combineReducers({
        profilePage: profileReducer,
        dialogsPage: dialogsReducer,
        sidebar: sidebarReducer,
        usersPage: usersReducer,
        auth: authReducer,
        app: apphReducer, //  <--- наш редьюсер
        form: formReducer
    
    }); //объединяем редьюсеры
    ...
  6. Теперь осталось доделать наше взаимодействие с компонентой App. Для этого в файле App.js создаем mapStateToProps и конектим его вместо null, а также заменяем в mapDispatchToProps getAuthUserData на нашу новую санку initializeApp, импортируя ее из нашего нового редьюсера (напомим, что getAuthUserData теперь вошла внутрь нее):
    const mapStateToProps = (state) => ({
      initialized: state.app.initialized
    })
    
    export default compose (
     withRouter,
     connect(mapStateToProps, {initializeApp})) (App);

     

  7. Теперь также нашу новую санку прописываем в componentDidMount() вместо той же getAuthUserData(). А также в рендере добавляем условие, при котором, пока наш initialized из стейта false, отображается прелоадер. А после завершения выполнения санки

    initializeApp значение его смениться на true и загрузится основной код из рендера.

    lass App extends React.Component {
    
      componentDidMount() {
        this.props.initializeApp();
      }
      
      render() {
        if (!this.props.initialized) {
          return <Preloader/>
        }
    
        return (
          
            <div className="app-wrapper">
            <HeaderContainer />
              <Navbar />
    ...

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *