Detailed explanation of Redux usage

preface

This article summarizes the use of Redux, using a simple counter application introduction to the use of flux, Redux, React-Redux, Redux-Actions and other related libraries.

Initial code Below is the initial code for this example, an ordinary counter application that does not use Redux.

import React from 'react'class Calculate extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }
  increase = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  decrease = () => {
    this.setState({
      count: this.state.count - 1
    })
  }
  render() {
    return(
      <div>
        <h1>{this.state.count}</h1>
        <div>
          <button type="button" onClick={this.increase}>Increase</button>
          <button type="button" onClick={this.decrease}>Decrease</button>
        </div>
      </div>
    )
  }}export default Calculate
Copy the code

Flux

React is a one-way data flow. Component state maintenance is implemented by layer by layer transfer between parent and child components. When the application level is deep, this method becomes cumbersome. The community has proposed a number of solutions to this problem, and the current best practice is Redux.

Before introducing Redux, which is strictly a neat implementation of Flux, let’s use Flux to reconstruct the counter application.

The Flux process consists of four parts, action, Dispatcher, Store and View. In this example, we need to use two NPM packages, Flux and Events, to achieve this.

First, create the following directory on the base template

Actiontype.js is used to define constants and export them. In this example, actions are added and subtracted.

export const INCREASE = 'INCREASE'export const DECREASE = 'DECREASE'

Dispatcher.js is used to define and export dispatcher

import { Dispatcher } from 'flux'class CalculateDispatcherClass extends Dispatcher { handleAction(action) { this.dispatch({ type: action.type, payload: action.payload }) }}const CalculateDispatcher = new CalculateDispatcherClass()export default CalculateDispatcher Action.js defines actions using the imported action category and the dispatcher defined above.

Copy the code

import { INCREASE, DECREASE} from '.. /constants/actionTypes'import CalculateDispatcher from '.. /dispatcher/dispatcher'const action = { increase(value = 1) { CalculateDispatcher.handleAction({ type: INCREASE, payload: value }) }, decrease(value = 1) { CalculateDispatcher.handleAction({ type: DECREASE, payload: value }) }} export default action

Finally, integrate in store.js

import CalculateDispatcher from '.. /dispatcher/dispatcher'import { EventEmitter } from 'events'import { INCREASE, DECREASE} from '.. /constants/actionTypes'const store = { count: 0}class CalculateStoreClass extends EventEmitter { addIncreaseListener(callBack) { this.on(INCREASE, callBack) }

addDecreaseListener(callBack) { this.on(DECREASE, callBack) }

Copy the code

getStore() { return store }}const CalculateStore = new CalculateStoreClass()CalculateDispatcher.register((action) => { switch(action.type) { case INCREASE: store.count += action.payload CalculateStore.emit(INCREASE) break case DECREASE: store.count -= action.payload CalculateStore.emit(DECREASE) break default: return true } return true})export default CalculateStore

Finally, calculate.js holds our view component

import React from 'react'import Store from '.. /store/store'import Action from '.. /action/action'class Calculate extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } componentDidMount() { Store.addDecreaseListener(this.updateState) Store.addIncreaseListener(this.updateState) } updateState = () => { this.setState({ count: Store.getStore().count }) } increase = () => { Action.increase() } decrease = () => { Action.decrease() } render() { return( <div> <h1>{this.state.count}</h1> <div> <button type="button" onClick={this.increase}>Increase</button> <button type="button" onClick={this.decrease}>Decrease</button> </div> </div> ) }}export default CalculateCopy the code

Redux

After knowing Flux, Redux can be used. The difference between Redux and Flux lies in replacing the Dispatcher with reducer

First, let’s have a look at the project structure, which is basically the same as flux, but has replaced dispatcher with reducer

In this example, both Redux and React-Redux are used, which makes it easier to combine redux and React projects. Redux-actions are used, which makes it easier to determine the types in actions and reducer.

actionType.js

Export const INCREASE = 'INCREASE'export const DECREASE = 'DECREASE' action.js Uses redux-actions to create an actionCopy the code

import { INCREASE, DECREASE} from '.. /constants/actionTypes'import { createActions} from 'redux-actions'const Action = createActions({ [INCREASE]: (value = 1) => ({ payload: value }), [DECREASE]: (value = 1) => ({ payload: value })})export default Action

Reducer.js Again, the reducer is processed using redux-actions

import { INCREASE, DECREASE } from '.. /constants/actionTypes'import { handleActions} from 'redux-actions'const reducer = handleActions({ [INCREASE]: (state, action) => (Object.assign({}, state, { count: state.count + action.payload.payload})), [DECREASE]: (state, action) => (Object.assign({}, state, { count: state.count - action.payload.payload}))}, { count: 0})export default reducerCopy the code

Store.js creates a store using redux

import { createStore } from 'redux'import reducer from '.. /reducer/reducer'const store = createStore(reducer)export default storeCopy the code

Calculate.js uses react-redux to connect React and redux

import React from 'react'import Action from '.. /action/action'import { connect } from 'react-redux'class Calculate extends React.Component { increase = () => { this.props.increase() } decrease = () => { this.props.decrease() } render() { return( <div> <h1>{this.props.count}</h1> <div> <button type="button" onClick={this.increase}>Increase</button> <button type="button" onClick={this.decrease}>Decrease</button> </div> </div> ) }}const mapStateToProps = (state) => { return { count: state.count }}export default connect(mapStateToProps, Action)(Calculate)Copy the code

Finally, the store is passed in using the Provider in app.js

import React from 'react'import Calculate from './component/calculate'import { Provider } from 'react-redux'import store  from './store/store'class App extends React.Component { render() { return ( <Provider store={store}> <Calculate /> </Provider> ) }}export default AppCopy the code

This article is formatted using MDNICE