Add Redux support to Gatsby projects

  1. Dependency installation:

npm install redux react-redux

  1. Create the src/store directory and create the createStore.js file

Create createStore.js file and export createStore method

import { combineReducers } from 'redux'
import userReducer from './user.reducer'

export default combineReducers(userReducer)

  1. Create a reducers folder in the store directory to store reducers

src/store/reducers/user.reducer.js

export const InitialState = {
  email: '[email protected]',
  name: 'huiquan',
  avatar: 'https://api.realworld.io/images/demo-avatar.png',
  loginStatus: 0
}

export default (state = InitialState, action) => {
  switch (action.type) {
    case 'modify-email':
      return { ...state, email: action.payload }
    case 'modify-name':
      return { ...state, name: action.payload }
    case 'modify-login-status':
      return { ...state, loginStatus: action.payload }
    case 'login':
      return { ...state, ...action.payload, loginStatus: 1 }
    default:
      return state
  }
}

  1. Create rootReducer.js

src/store/reducers/root.reducer.js Merge and export the reducers in the reducers directory through the combineReducers method

import { combineReducers } from 'redux'
import userReducer from './user.reducer'

export default combineReducers({ userReducer })

  1. Configure the provider of the client, create a gatsby-browser.js file in the root directory, and export the wrapRootElement method

const React = require('react')
const Layout = require('./src/components/Layout').default

const { Provider } = require('react-redux')

const createStore = require('./src/store/createStore').default

module.exports = {
  wrapPageElement: ({ element }) => {
    return <Layout>{element}</Layout>
  },
  wrapRootElement: ({ element }) => {
    return <Provider store={createStore()}>{element}</Provider>
  }
}

  1. Configure the provider on the server side and create a gatsby-ssr.js file in the root directory

const React = require('react')
const { Provider } = require('react-redux')
const createStore = require('./src/store/createStore').default

module.exports = {
  wrapRootElement: ({ element }) => {
    return <Provider store={createStore()}>{element}</Provider>
  }
}

  1. Use the data in the store and modify the data in the page or component

We introduce useDispatch, useSelector hook functions in the component, and use them to modify the state in the store:

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'

export default function Header () {
  const userReducer = useSelector(state => state.userReducer)
  const dispatch = useDispatch()

  return (
    <nav className='navbar navbar-light'>
      <div className='container'>
        <a className='navbar-brand' href='index.html'>
          conduit
        </a>
        <ul className='nav navbar-nav pull-xs-right'>
          <li className='nav-item'>
            {/* Add "active" class when you're on that page" */}
            <a className='nav-link active'>Home</a>
          </li>
          {userReducer.loginStatus === 1 && (
            <li className='nav-item'>
              <a className='nav-link'>
                {' '}
                <i className='ion-compose' />
                &nbsp;New Article{' '}
              </a>
            </li>
          )}
          <li className='nav-item'>
            <a className='nav-link'>
              {' '}
              <i className='ion-gear-a' />
              &nbsp;Settings{' '}
            </a>
          </li>
          {userReducer.loginStatus === 0 && (
            <>
              <li className='nav-item'>
                <a
                  onClick={() => dispatch({ type: 'login' })}
                  className='nav-link'
                >
                  Sign in
                </a>
              </li>
              <li className='nav-item'>
                <a className='nav-link'>Sign up</a>
              </li>
            </>
          )}
          {userReducer.loginStatus === 1 && (
            <li className='nav-item'>
              <a
                className='nav-link ng-binding'
                ui-sref-active='active'
                ui-sref='app.profile.main({ username: $ctrl.currentUser.username })'
              >
                <img className='user-pic' src={userReducer.avatar} />
                {userReducer.name}
              </a>
            </li>
          )}
        </ul>
      </div>
    </nav>
  )
}

  1. Add redux's asynchronous processing support, redux-saga

npm install redux-saga

Create the src/store/sagas folder, create src/store/sagas/user.saga.js and src/store/sagas/root.saga.js:

// src/store/sagas/user.saga.js
import axios from 'axios'
import { takeEvery, put, delay } from 'redux-saga/effects'

function* login_async (action) {
  console.log(action.payload)
  const { data } = yield axios.post(
    'https://api.realworld.io/api/users/login',
    {
      user: action.payload.user
    }
  )
  yield put({ type: 'login', payload: data.user })
}
export default function* userSaga () {
  yield takeEvery('login_async', login_async)
}
// src/store/sagas/root.saga.js
import { all } from 'redux-saga/effects'
import userSaga from './user.saga'

export default function* rootSga () {
  yield all([userSaga()])
}

In page components use:

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'

export default function Header () {
  const userReducer = useSelector(state => state.userReducer)
  const dispatch = useDispatch()

  return (
    <nav className='navbar navbar-light'>
      <div className='container'>
        <a className='navbar-brand' href='index.html'>
          conduit
        </a>
        <ul className='nav navbar-nav pull-xs-right'>
          <li className='nav-item'>
            {/* Add "active" class when you're on that page" */}
            <a className='nav-link active'>Home</a>
          </li>
          {userReducer.loginStatus === 1 && (
            <li className='nav-item'>
              <a className='nav-link'>
                {' '}
                <i className='ion-compose' />
                &nbsp;New Article{' '}
              </a>
            </li>
          )}
          <li className='nav-item'>
            <a className='nav-link'>
              {' '}
              <i className='ion-gear-a' />
              &nbsp;Settings{' '}
            </a>
          </li>
          {userReducer.loginStatus === 0 && (
            <>
              <li className='nav-item'>
                <a
                  onClick={() => dispatch({ type: 'login' })}
                  className='nav-link'
                >
                  Sign in
                </a>
              </li>
              <li className='nav-item'>
                <a
                  onClick={() =>
                    dispatch({
                      type: 'login_async',
                      payload: {
                        user: {
                          email: '[email protected]',
                          password: '111111'
                        }
                      }
                    })
                  }
                  className='nav-link'
                >
                  Sign up
                </a>
              </li>
            </>
          )}
          {userReducer.loginStatus === 1 && (
            <li className='nav-item'>
              <a
                className='nav-link ng-binding'
                ui-sref-active='active'
                ui-sref='app.profile.main({ username: $ctrl.currentUser.username })'
              >
                <img className='user-pic' src={userReducer.image} />
                {userReducer.username}
              </a>
            </li>
          )}
        </ul>
      </div>
    </nav>
  )
}

Guess you like

Origin blog.csdn.net/u011024243/article/details/129650609