React项目引入Redux、使用redux-thunk、使用react-redux、配置装饰器

安装Redux:

cnpm i redux --save

 

一、手动连接Redux处理同步,示例:

 

在src目录下有index.js、app.js,再新建index.redux.js,分别修改这几个文件的内容如下:

 

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import App from './App';
import { counter, addGun, removeGun } from './index.redux'

// 新建Store,并且以组件属性的形式传入组件里:
const store = createStore(counter)

function render() {
  ReactDOM.render(
    <React.StrictMode>
      <App 
        store={store} 
        addGun={addGun}
        removeGun={removeGun}
      />
    </React.StrictMode>,
    document.getElementById('root')
  );
}
render()

// 用subscribe订阅render函数,当状态变化时render会重新执行,重新渲染整个页面:
store.subscribe(render)

 

app.js:

import React from 'react'

class App extends React.Component {
  // constructor(props) {
  //   super(props)
  // }
  render() {
    // 通过属性获取store以及addGun、removeGun这两个操作函数,再通过store获取初始状态和dispatch方法:
    const store = this.props.store
    const num = store.getState()
    const addGun = this.props.addGun
    const removeGun = this.props.removeGun
    return (
      <div>
        <h1>现在有机枪{num}把</h1>
        <button onClick={() => store.dispatch(addGun())}>申请武器</button>
        <button onClick={() => store.dispatch(removeGun())}>上交武器</button>
      </div>
    )
  }
}

export default App

 

index.redux.js:

// 定义常量:
const ADD_GUN = '加机关枪'
const REMOVE_GUN = '减机关枪'

// reducer:
export function counter(state = 0, action) {
  switch (action.type) {
    case ADD_GUN:
      return state + 1
    case REMOVE_GUN:
      return state - 1
    default:
      return 10
  }
}

// 把对象变成函数返回值:
// action creator,专门创建action:
export function addGun() {
  return {type: ADD_GUN}
}
export function removeGun() {
  return {type: REMOVE_GUN}
}

// 只要提交action,reducer就会执行,reducer会获取现在的状态和action,action就是{type: ADD_GUN}或{type: REMOVE_GUN},然后判断type,处理完返回新的状态,当状态变化时,用subscribe订阅drender函数会重新执行,重新渲染整个页面:

 

二、手动连接Redux处理异步,需要redux-thunk插件,示例:

 

安装redux-thunk插件:

cnpm i redux-thunk --save

 

下载Redux-DevTools,拖动到chrome窗口里来安装:

https://cdn1.zzzmh.cn/chrome/v2/crx/lmhkpmbekcpmknklioeibfkpmmfibljd/lmhkpmbekcpmknklioeibfkpmmfibljd.zip?download=lmhkpmbekcpmknklioeibfkpmmfibljd.zip

 

在src目录下有index.js、app.js、index.redux.js,分别修改这几个文件的内容如下:

 

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'
import App from './App';
import { counter, addGun, removeGun, addGunAsync } from './index.redux'

// 新建Store,并且以组件属性的形式传入组件里:
const store = createStore(counter, compose(
  applyMiddleware(thunk),
  window.devToolsExtension ? window.devToolsExtension() : () => {}
)) //compose可以组合函数

applyMiddleware(thunk)

function render() {
  ReactDOM.render(
    <React.StrictMode>
      <App 
        store={store} 
        addGun={addGun}
        removeGun={removeGun}
        addGunAsync={addGunAsync}
      />
    </React.StrictMode>,
    document.getElementById('root')
  );
}
render()

// 用subscribe订阅render函数,当状态变化时render会重新执行,重新渲染整个页面:
store.subscribe(render)

 

app.js:

import React from 'react'

class App extends React.Component {
  // constructor(props) {
  //   super(props)
  // }
  render() {
    // 通过属性获取store以及addGun、removeGun这两个操作函数,再通过store获取初始状态和dispatch方法:
    const store = this.props.store
    const num = store.getState()
    const addGun = this.props.addGun
    const removeGun = this.props.removeGun
    const addGunAsync =this.props.addGunAsync
    return (
      <div>
        <h1>现在有机枪{num}把</h1>
        <button onClick={() => store.dispatch(addGun())}>申请武器</button>
        <button onClick={() => store.dispatch(removeGun())}>上交武器</button>
        <button onClick={() => store.dispatch(addGunAsync())}>拖两天再给</button>
      </div>
    )
  }
}

export default App

 

index.redux.js:

// 定义常量:
const ADD_GUN = '加机关枪'
const REMOVE_GUN = '减机关枪'

// reducer:
export function counter(state = 0, action) {
  switch (action.type) {
    case ADD_GUN:
      return state + 1
    case REMOVE_GUN:
      return state - 1
    default:
      return 10
  }
}

// 把对象变成函数返回值:
// action creator,专门创建action:
export function addGun() {
  return {type: ADD_GUN}
}
export function removeGun() {
  return {type: REMOVE_GUN}
}

// 只要提交action,reducer就会执行,reducer会获取现在的状态和action,action就是{type: ADD_GUN}或{type: REMOVE_GUN},然后判断type,处理完返回新的状态,当状态变化时,用subscribe订阅drender函数会重新执行,重新渲染整个页面

export function addGunAsync() {
  return dispatch => {
    setTimeout(() => {
      dispatch(addGun())
    }, 2000)
  }
}

 

三、使用react-redux连接Redux处理同步和异步,示例:

 

安装react-redux:

cnpm i react-redux --save

 

在src目录下有index.js、app.js、index.redux.js,分别修改这几个文件的内容如下:

 

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import App from './App';
import { counter } from './index.redux'

// 新建Store,并且以组件属性的形式传入组件里:
const store = createStore(counter, compose(
  applyMiddleware(thunk),
  window.devToolsExtension ? window.devToolsExtension() : () => {}
)) //compose可以组合函数

applyMiddleware(thunk)

ReactDOM.render(
  (<Provider store={store}>
    <App />
  </Provider>),
  document.getElementById('root')
); //Provider组件在应用最外层,传入store,并且只需要用一次,Connect负责从外部获取组件需要的参数,Connect可以用装饰器的方式来写

// 用subscribe订阅render函数,当状态变化时render会重新执行,重新渲染整个页面:
// store.subscribe(render)

 

app.js:

import React from 'react'
import { connect } from 'react-redux'
import { addGun, removeGun, addGunAsync } from './index.redux'

class App extends React.Component {
  // constructor(props) {
  //   super(props)
  // }
  render() {
    // 通过属性获取store以及addGun、removeGun这两个操作函数,再通过store获取初始状态和dispatch方法:
    return (
      <div>
        <h1>现在有机枪{this.props.num}把</h1>
        <button onClick={this.props.addGun}>申请武器</button>
        <button onClick={this.props.removeGun}>上交武器</button>
        <button onClick={this.props.addGunAsync}>拖两天再给</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {num: state} //把状态放到属性里
}
const actionCreators = { addGun, removeGun, addGunAsync } //把方法传入

App = connect(mapStateToProps, actionCreators)(App) //先执行connect,再把App当做参数传入,这就是一个装饰器
export default App

 

index.redux.js:

// 定义常量:
const ADD_GUN = '加机关枪'
const REMOVE_GUN = '减机关枪'

// reducer:
export function counter(state = 0, action) {
  switch (action.type) {
    case ADD_GUN:
      return state + 1
    case REMOVE_GUN:
      return state - 1
    default:
      return 10
  }
}

// 把对象变成函数返回值:
// action creator,专门创建action:
export function addGun() {
  return {type: ADD_GUN}
}
export function removeGun() {
  return {type: REMOVE_GUN}
}

// 只要提交action,reducer就会执行,reducer会获取现在的状态和action,action就是{type: ADD_GUN}或{type: REMOVE_GUN},然后判断type,处理完返回新的状态,当状态变化时,用subscribe订阅drender函数会重新执行,重新渲染整个页面

export function addGunAsync() {
  return dispatch => {
    setTimeout(() => {
      dispatch(addGun())
    }, 2000)
  }
}

 

四、使用react-redux连接Redux处理同步和异步,并使用装饰器优化connect代码,示例:

 

弹出个性化配置:

npm run eject 或 yarn eject

 

安装装饰器插件:

cnpm i @babel/plugin-proposal-decorators --save

 

打开项目根目录的config-overrides.js

const { override, fixBabelImports } = require('customize-cra');
module.exports = override(
  fixBabelImports(
    'import', 
    {
      libraryName: 'antd-mobile',
      style: 'css'
    }
  ),
);

改为

const { override, fixBabelImports, addDecoratorsLegacy } = require('customize-cra');

module.exports = override(
  fixBabelImports(
    'import', 
    {
      libraryName: 'antd-mobile',
      libraryDirectory: "es",
      style: 'css'
    }
  ),
  addDecoratorsLegacy()
);

 

在src目录下有index.js、app.js、index.redux.js,分别修改这几个文件的内容如下:

 

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import App from './App';
import { counter } from './index.redux'

// 新建Store,并且以组件属性的形式传入组件里:
const store = createStore(counter, compose(
  applyMiddleware(thunk),
  window.devToolsExtension ? window.devToolsExtension() : () => {}
)) //compose可以组合函数

applyMiddleware(thunk)

ReactDOM.render(
  (<Provider store={store}>
    <App />
  </Provider>),
  document.getElementById('root')
); //Provider组件在应用最外层,传入store,并且只需要用一次,Connect负责从外部获取组件需要的参数,Connect可以用装饰器的方式来写

// 用subscribe订阅render函数,当状态变化时render会重新执行,重新渲染整个页面:
// store.subscribe(render)

 

app.js:

import React from 'react'
import { connect } from 'react-redux'
import { addGun, removeGun, addGunAsync } from './index.redux'

@connect(
  // 把state什么属性放到props里:
  state => ({num: state}),
  // 把state中的什么方法放到props里,会自动dispatch:
  { addGun, removeGun, addGunAsync },
)
class App extends React.Component {
  // constructor(props) {
  //   super(props)
  // }
  render() {
    // 通过属性获取store以及addGun、removeGun这两个操作函数,再通过store获取初始状态和dispatch方法:
    return (
      <div>
        <h1>现在有机枪{this.props.num}把</h1>
        <button onClick={this.props.addGun}>申请武器</button>
        <button onClick={this.props.removeGun}>上交武器</button>
        <button onClick={this.props.addGunAsync}>拖两天再给</button>
      </div>
    )
  }
}

export default App

 

index.redux.js:

// 定义常量:
const ADD_GUN = '加机关枪'
const REMOVE_GUN = '减机关枪'

// reducer:
export function counter(state = 0, action) {
  switch (action.type) {
    case ADD_GUN:
      return state + 1
    case REMOVE_GUN:
      return state - 1
    default:
      return 10
  }
}

// 把对象变成函数返回值:
// action creator,专门创建action:
export function addGun() {
  return {type: ADD_GUN}
}
export function removeGun() {
  return {type: REMOVE_GUN}
}

// 只要提交action,reducer就会执行,reducer会获取现在的状态和action,action就是{type: ADD_GUN}或{type: REMOVE_GUN},然后判断type,处理完返回新的状态,当状态变化时,用subscribe订阅drender函数会重新执行,重新渲染整个页面

export function addGunAsync() {
  return dispatch => {
    setTimeout(() => {
      dispatch(addGun())
    }, 2000)
  }
}

 

posted @ 2021-03-08 23:37  starlog  阅读(285)  评论(0编辑  收藏  举报