React Project Practices (1) Start with framework configuration

Let’s talk about the design of a landing page. In previous projects I have written, I have placed forms on a single page without taking into account the loading prompt when the user is waiting. This redesign will show component and control separation and state management using state machines

State analysis

A few days ago just saw an article front-end state management please think again, feel very interesting, the author of the original state machine using the idea, preconceived of all states and state migration, elegant management page login state to avoid the use of too many variables. This article refers to the author’s ideas and code to achieve a simple login page. The status analysis is as follows:

  • The initial login page is the login form that displays the login form
  • After submitting the data process, the page changes to waiting for data response state.
    • The data response has two states: the success page jumps to the home page; The Failure page displays an error
    • If the login is successful, you can log in again only after you have logged out
    • When login fails, submit again to loading state.
  • Logout returns to the login Form state

Again, this is an implementation that mimics the Nuggets APP login page:

Defining the state machine

const machine = {
  states: {
    'login form': {
      submit: 'loading'
    },
    loading: {
      success: 'profile'.failure: 'error'
    },
    profile: {
      viewProfile: 'profile'.logout: 'login form'
    },
    error: {
      submit: 'loading'}}}Copy the code

Implement a state control function that returns the next state

const stateTransformer = function(currentState, stepUp) {
  let nextState
  if (machine.states[currentState][stepUp]) {
    nextState = machine.states[currentState][stepUp]
  }
  console.log(`${currentState} + ${stepUp} --> ${nextState}`)
  return nextState || currentState
}
Copy the code

We store the variables of state control in Redux, and define a simple Auth module as follows. The stateChanger pure function is used to control the state transition of currentState, and the state transformation is carried out every time the result of operation is returned

export default {
  namespace: 'auth'.state: {
    currentState: 'login form'
  },
  reducers: {
    stateChanger(state, {stepUp}) {
      return {
        ...state,
        currentState: stateTransformer(state.currentState, stepUp)
      }
    }
  },
  effects: dispatch= > ({
  async loginByPhoneNumber(playload, state) {
    dispatch.auth.stateChanger({stepUp: 'submit'})
    let {data} = await api.auth.loginByPhoneNumber(playload)
    if (data.s === 0) {
      dispatch.auth.stateChanger({stepUp: 'success'})
      saveData('juejin_token', data.token)
    } else {
      dispatch.auth.stateChanger({stepUp: 'failure'})
      Toast.info('Wrong username or password'.2)}}})}Copy the code

So within components, it’s easy to write a component that controls state changes


  render() {
    let {currentState} = this.props
    return(<> {() => {switch (currentState) {case 'loading': return (// loading to display components) case 'profile': Return < Redirect to = {} '/' / > / / returns the default home page: return (/ / login form)}}) ()}} < / a >)Copy the code

Specific Configuration Supplement

In order to coordinate with user login authentication of the project, we re-set up a local service to configure proxy forwarding of routes in React. Specifically, we created a file SRC/setupproxy. js in the root directory to forward/API requests to the server

const proxy = require('http-proxy-middleware')
module.exports = function(app) {
  app.use(proxy('/api', {target: 'http://localhost:8989/'.changeOrigin: true}}))Copy the code

Services/API defines the data interface

export async function loginByPhoneNumber({phoneNumber, password}) {
  return post('/api/auth/type/phoneNumber', {
    body: {
      phoneNumber,
      password
    }
  })
}
Copy the code

The back end implements a simple middleware route

const Koa = require('koa')
const router = require('./router')
router.post('/auth/type/phoneNumber'.async (ctx, next) => {
  var {phoneNumber, password} = await parse.json(ctx.req)
  if (phoneNumber === '15111111111' && password === '123456') {
    let token = generateToken({uid: phoneNumber, password})
    ctx.response.body = JSON.stringify({
      s: 0.m: 'Account login success error'.d: ' ',
      token
    })
  } else {
    ctx.response.body = JSON.stringify({s: 1.m: 'Account information error'.d: ' '})}})Copy the code

Project address is a small personal practice, we have a better approach in the management of the login page? What other complications need to be considered