cookie, login, auth/me

  1. Создаем файл для редьюсера – src/redux/auth-reducer.js
  2. Создаем стейт с теми же свойствами, которые мы будем получать, согласно API-документации. При этом “зануляем” их.
  3. let initialState = {
          userId: null,
          email: null,
          login: null,
          isAuth: false
    }
    isAuth – это не из пришедшего объекта, а для удобства нам на будушее.
  4. Создадим переменную с типом экшна, приходящего когда мы авторизированы (в самом верху файла):
    const SET_USER_DATA = 'SET_USER_DATA';
  5. Создаем редьюсер authReducer. В нем мы создаем копию state, а следующей строчкой делаем деструктуризацию объекта data, который пришел в экшене. В резульате userId, email, login перезатрут аналогичные значения в копии state, так как эта строчка кода ниже. А также меняем потом в копии state значение свойства isAuth на false.
    const authReducer = (state = initialState, action) => {
        switch(action.type) {
            case SET_USER_DATA:
                return {
                    ...state,
                    ...action.data,
                    isAuth: true
                }
        default:
            return state;
        }
    }
    export default authReducer;
  6. В самом низу файла перед экспортом редьюсера создаем экшн-криэйтер, который будет называться setUserData. В него приходят данные userId, email, login (это мы их передаем в разобраном виде, хотя можно было и объектом). Экшн-криэйтер будет возвращать экшн, который содержит type: SET_USER_DATA, а также объект с данными data: {userId, email, login}. Можна было бы передать одним объеком data, но тогда человеку, который будет вызывать экшн-криэйтер будет не до конца понятно, что за data и какого она типа должна быть (такую проблему возможно решить языком со строгой типизацией, но это в будущем). Этот  созданный экшн потом будет задиспатчен в редьюсер.
    export const setUserData = (userId, email, login) => ({type: SET_USER_DATA, data: {user, email, login} })
  7. В файле src/redux/redux-store.js , где мы создавали точку входа редьюсеров (т.е. объединяли их при помощи combineReducers) делаем импорт нашего нового редьюсера и добавляем его в combineReducers.
    ...
    import authReducer from "./auth-redux";
    ....
    let reducers = combineReducers({
        ...
        auth: authReducer,
        ...
    
    });
    
    let store = createStore(reducers, applyMiddleware(thunkMiddleware));
    
    export default store;
  8. Идем в нашу презентационную компоненту Header.jsx и там создаем новый блок div, а в нем Navlink на страницу /login
  9. Создаем контейнерную компоненту для Header – HeaderContainer, которая будет классовой. Заменяем в App.js вывод на нашу контейнерную компоненту вместо презентационной. Теперь, благодаря контейнерной компоненте, у нас есть возможность делать запросы, не загрязняя презентационную компоненту. Согласно документации делаем GET запрос на auth/me. Вторым параметром в GET запросе нам нужно передать специальный объект, в котором сидят настройки запроса {withCredentials: true}. Благодаря этому запрос уйдет авторизованым на сервер.
    import....
    
    class HeaderContainer extends React.Component {
      componentDidMount() {
         axios.get('https://social-network.samuraijs.com/api/1.0/auth/me', {
            withCredentials: true
         })
      }
    
      render() {
        return  <Header {...this.props} />
      }
    }
    export default HeaderContainer;
    
  10. Теперь наш Header узнал, что мы авторизованы и эту информацию можно задиспатчить в редьюсеры. Для этого мы конннектим нашу контейнерную компоненту.
    const mapeStateToProps = (state) => ({});
    
    export default connect(mapeStateToProps, {getAuthUserData}) (HeaderContainer);
  11. Теперь в компоненте добавляем, что если мы авторизированы (response.data.resultCode === 0), то деструктуризируем наш объект data (правильную последовательность id, email и login можно в редьюсере подсмотреть) и диспатчим авторизационные данные:
    import....
    
    class HeaderContainer extends React.Component {
      componentDidMount() {
         axios.get('https://social-network.samuraijs.com/api/1.0/auth/me', {
            withCredentials: true
         })
    
            .then(response => {
               
               if (response.data.resultCode === 0) {
                  let (id, login, email) = response.data.data;
                  this.props.setAuthUserData(id, email, login);
               }
      }
    
      render() {
        return  <Header {...this.props} />
      }
    }
    ...
    Первая data – это стандартная аксиовская структура, а вторая – это бэкендшик так назвал объект. Поэтому и получилось две data подряд.
  12. Теперь, если мы залогинены и хоим показать это на странице (например, выводить логин пользователя вместо ссылки на страницу /login в header), то добавляем в mapStateToProps данные из стейта, которые мы получим в HeaderContainer и через пропсы прокиним в Header.
    const mapeStateToProps = (state) => ({
      isAuth: state.auth.isAuth,
      login: state.auth.login
    });

     

  13. В Header теперь можно через тернарный оператор вывести тот или иной результат, зависимо от авторизации. Вот так будет выглядеть весь Header.jsx:
    import React from 'react';
    import s from './Header.module.css';
    import { NavLink } from 'react-router-dom/cjs/react-router-dom.min';
    
    const Header = (props) => {
      return  (
        <header className={s.header}>
            <img src='https://w0.pngwave.com/png/935/389/university-of-amikom-yogyakarta-condongcatur-logo-social-media-social-media-png-clip-art.png' />
            <div className={s.loginBlock}>
              {props.isAuth ? props.login
                  : <NavLink to={'/login'}>Login</NavLink> 
              }
            </div>
          </header>
        )
    }
    
    export default Header;

     

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

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