redux-thunk使用教程

从无到有一步一步创建一个react-redux、redux-thunk使用教程:本教程GitHub地址:

https://github.com/chunhuigao/react-redux-thunk

创建react工程

在电脑上找一个文件夹,在命令窗使用create-react-app 创建我的react工程;这一步应该会的
create-react-app study-redux
复制代码
看到下面这个图证明我创建完毕

启动react服务

在创建任务完成后进入我的创建的react工程,然后npm start运行,接着在浏览器 http://localhost:3000/我应用该可以看到下面图片的场景

安装redux

要使用redux我需要使用npm将redux包安装到我的react工程中
在react工程的命令窗输入
npm install redux
npm install react-redux
npm install redux-thunk
复制代码
如果报错,请使用淘宝代理cnpm安装。等待安装完毕,从新npm start启动项目

我的工程目录

删除无用的代码

将app.js中html结构代码删除,代码如下:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      
"App"> {/*
"App-header"> "App-logo" alt="logo" />

Edit src/App.js and save to reload.

"App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React
*/}
); } } export default App; 复制代码
这段代码对我学习redux没什么用,我喜欢代码简洁一点,所以删除了

创建第一个组件

在工程目录src/component中创建一个名为hello的文件夹,在hello文件夹中创建一个名为hello.js的文件。
在hello.js写如下代码:
import React, { Component } from 'react'

class Hello extends Component {
  render() {
    return (
      

学习redux

) } } export default Hello 复制代码
在app.js中引入hello这个组件
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Hello from './component/hello/hello.js'
class App extends Component {
  render() {
    return (
      
"App">
); } } export default App; 复制代码
在浏览器中我应该可以看到“学习redux”这句文案了。

添加第一个事件

给hello添加一个按钮,点击按钮可以改变“学习redux”这句文案;hello.js具体代码如下:
import React, { Component } from 'react'
import './hello.css'
 class Hello extends Component {
  constructor(props){
    super(props)
    this.state = {
      title:'学习redux'
    }
  }
  changeTitle(){
    let title = '学习redux' + Math.ceil(Math.random()*100)
    this.setState({
      title:title
    })
  }
  render() {
    return (
      

{this.state.title}

) } } export default Hello 复制代码

开始使用redux

下面这个流程刚开始接触redux可能云里雾里。但要坚持,跟着我的操作,你一定会看到结果的

index.js引用一下内容

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from 'react-redux'  //新引入
import {createStore} from 'redux'   //新引入
import rootReducer from './rootReducer.js'  //新引入

const store = createStore(rootReducer)
ReactDOM.render(

    

, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

复制代码
redux和react-redux之前安装过,引用后会报错,原因是引入的rootReducer.js这个文件需要创建;

创建rootReducer

在src文件夹创建rootReducer.js文件代码如下:
文件中combineReducers将拆分的页面单独reducer合并为一个大的reducer
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
const rootReducer = combineReducers({
    helloReducer
})
export default rootReducer
复制代码
这里面引入了一个helloReducer.js,这里我在hello.js同级文件夹创建helloReducer.js

创建helloReducer.js

reducer里面定义页面初始数据,在根据action.type操作state;具体代码如下:
const initState = {
    name:'hello,redux'
}
export default (state=initState,action) => {
    switch (action.type) {
        case 'CHANGE_NAME':
            return {...state,name:action.text}
        default:
            return state;
    }
}
复制代码
然后将reducer数据绑定到组件中,这里需要用到react-redux中的connect函数

数据绑定到组件

这部分是在hello.js中进行的;具体代码如下:
import React, { Component } from 'react'

//引用connect
import {connect} from 'react-redux'

import './hello.css'
 class Hello extends Component {
  constructor(props){
    super(props)
    this.state = {
      title:'学习redux'
    }
  }
  changeTitle(){
    let title = '学习redux' + Math.ceil(Math.random()*100)
    this.setState({
      title:title
    })
   
  }
  render() {
//此处打印this.props应该可以看到helloProp这个对象了,证明数据已经挂在到组件紫红
    console.log(this.props)
    let {prop} = this.props
    return (
      

{this.state.title}

我是来自redux数据{prop.name}

) } } //mapStateToProps是connect一个参数, 作用到将store中的数据作为 props 绑定到组件上 const mapStateToProps = (state, ownProps) => { return { helloProp: state.helloReducer//helloReducer是在rootReducer中的名 } } //通过connect高阶函数绑定数据 export default connect(mapStateToProps)(Hello) 复制代码
数据已经绑定到组件了,怎么操作改变数据呢?需要用到action了

创建helloAction.js

在hello.js同级不目录创建helloAction.js;action主要负责发出动作指令,定义所有事件行为的;具体代码如下:
const helloAction = {
    changeName:(text)=>({
        type:"CHANGE_NAME",
        text:text,
        mate:'用于改变helloReducer中name值'
    })
}
export default helloAction
复制代码
文件创建好怎么用呢?数据可以绑定到组件,action也是可以绑定到组件的,使用redux中bindActionCreators,具体代码看hello.js

将action绑定到组件

在hello.js引入新创建的helloAction.js,哎,看代码吧
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
//引入helloAction
import helloAction from './helloAction.js'
import './hello.css'
 class Hello extends Component {
  constructor(props){
    super(props)
    this.state = {
      title:'学习redux'
    }
  }
  changeTitle(){
    let title = '学习redux' + Math.ceil(Math.random()*100)
    this.setState({
      title:title
    })
   
  }
  render() {
    //此处打印,应该可以看到actions
    console.log(this.props)
    let {prop} = this.props
    return (
      

{this.state.title}

我是来自redux数据{prop.name}

) } } const mapStateToProps = (state, ownProps) => { return { prop: state.helloReducer } } //使用mapDispatchToProps绑定helloAction const mapDispatchToProps = (dispatch, ownProps) => { return { actions:bindActionCreators(helloAction,dispatch) } } //将mapDispatchToProps作为参数给connect export default connect(mapStateToProps,mapDispatchToProps)(Hello) 复制代码
改写changeTitle事件,修改redux传过来的数据
changeTitle(){
    let title = '学习redux' + Math.ceil(Math.random()*100)
    // this.setState({
    //   title:title
    // })
    let {actions} = this.props
    actions.changeName(title)
   
  }
复制代码
效果图
孤例不为证,这个是在hello.js操作helloReducer的数据,不需要redux这么麻烦也可以搞定。下面我使用redux操作一下其他组件修改HelloReducer中的数据
移步GitHub点个start

创建other组件

在component文件夹中创建other文件夹,在other文件夹创建other.js;具体代码如下图
在app.js引入other.js
import React, { Component } from 'react';
import Hello from './component/hello/hello.js'
import Other from './component/other/other.js'
import './App.css';

class App extends Component {
  render() {
    return (
      
"App">
); } } export default App; 复制代码

other具体代码

import React, { Component } from 'react'
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import helloAction from '../hello/helloAction.js'
 class Other extends Component {
  changeName(){
    let {helloAction} = this.props;
    let text = 'other' + (Math.random() *100)
    helloAction.changeName(text)
  }
  render() {
    let {otherProp} = this.props
    console.log(this.props)
    return (
      

我是其他组件

) } } const mapStateToProps = (state, ownProps) => { return { otherProp: state.helloReducer } } const mapDispatchToProps = (dispatch, ownProps) => { return { helloAction:bindActionCreators(helloAction,dispatch) } } export default connect(mapStateToProps,mapDispatchToProps)(Other) 复制代码
点击按钮,同样可以操作helloReducer.js的数据,mapStateToProps只能绑定一个数据源吗?如果other也有reducer怎么办呢?

组件上绑定多个数据

在other.js同级目录创建otherReducer.js具体代码如下:
const initState = {
    title:'我是otherReducer数据'
}

export default (state=initState,action) => {
    switch (action.type) {
        case "CHANGE_TITLE":
            return {...state,title:action.text}
        default:
            return state
    }
}
复制代码
在rootReducer.js中引用otherReducer.js,rootReducer代码如下:
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
import otherReducer from './component/other/otherReducer.js'
const rootReducer = combineReducers({
    helloReducer,
    otherReducer
})
export default rootReducer
复制代码
在other.js的mapStateToProps中绑定reducer数据
const mapStateToProps = (state, ownProps) => {
    return {
        helloProp: state.helloReducer,
        otherProp: state.otherReducer
    }
}
复制代码
在render打印this.props试试?
  render() {
    let {helloProp,otherProp} = this.props
    console.log(this.props)
    return (
      

我是其他组件

{otherProp.title}
) } 复制代码
到此,可以使用redux了。但这写只能执行同步操作,异步操作需要要结合redux-thunk或者redux-saga了;

redux异步操作

也是写一个简单的例子
在index.js引入redux-thunk
//注释import {createStore} from 'redux' 
//新增
import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'

//注释 const store = createStore(rootReducer)
//新增
const store = createStore(rootReducer,applyMiddleware(thunk))
复制代码
在component文件夹下创建example文件夹,在example文件夹创建example.js、exampleAction.js、exampleReducer.js具体代码如下:
example.js代码:
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import exampleAction from './exampleAction.js'
class Example extends Component {
  asyncFn(){
    let {exampleAction} = this.props
    exampleAction.asyncThing()
    console.log(this.props)
  }
  render() {
    let {exampleProp} = this.props
    return (
      

异步操作

{exampleProp.text}

) } } const mapStateToProps = (state, ownProps) => { return { exampleProp: state.exampleReducer } } const mapDispatchToProps = (dispatch, ownProps) => { return { exampleAction:bindActionCreators(exampleAction,dispatch) } } export default connect(mapStateToProps,mapDispatchToProps)(Example) 复制代码
exampleReducer.js代码:
const initState={
    text:'我是用来测试异步操作的',
    sign:null
}
export default (state=initState,action) =>{
    console.log(action)
    switch (action.type) {
        case 'SUCCESS':
            return {...state,text:action.text,sign:'success'}
        case 'ERROR':
            return {...state,text:action.text,sign:'error'}
        default:
            return state
    }
}
复制代码
exampleAction.js
 const exampleAction = {
    asyncThing:()=>{
        return (dispatch, getState) =>{
            // fetch('https://hacker-news.firebaseio.com/v0/jobstories.json')
            //     .then(res => {
            //         dispatch(exampleAction.asyncSuccess('我是成功回调'))  
            //     }).catch(e => {
            //         dispatch(exampleAction.asyncError('我是成功回调'))  
            // });
            setTimeout(() => {
                let sign = Math.random() >= 0.5 ? true : false;
                console.log(sign)
                sign ? dispatch(exampleAction.asyncSuccess('我是成功数据'))  : dispatch(exampleAction.asyncError('我是失败数据'))  
            }, 2000);
        }
    },
    asyncSuccess:(text)=>({
        type:'SUCCESS',
        text:text,
        mate:'异步成功操作'
    }),
    asyncError:(text)=>({
        type:'ERROR',
        text:text,
        mate:'异步成功操作'
    })
}
export default exampleAction
复制代码
exampleReducer.js同样需要引入rootReduder.js中。
rootReducer代码:
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
import otherReducer from './component/other/otherReducer.js'
import exampleReducer from './component/example/exampleReducer.js'
const rootReducer = combineReducers({
    helloReducer,
    otherReducer,
    exampleReducer
})
export default rootReducer
复制代码
在app.js引入新建是example组件,应该可以看待如下界面
redux异步搞定了。

结束语:

不知我描述的清楚不清楚,希望这篇文章能不能帮到你。本人学识有限,如有文档中不规范或者误人子弟的错误言论,请指正。感谢你花时间阅读这篇文章,谢谢!




转载于:https://juejin.im/post/5c446a7a51882524b4074354

你可能感兴趣的:(redux-thunk使用教程)