• React-redux及异步获取数据20分钟快速入门


    一, 写在前面

    1. 前面我写过一个vuex10分钟入门 传送门

    2. React-redux网上有好多文档,又臭又长,明明很简单的问题,硬是让新人更晕了~, 我写这个文章的目的是让新人在20分钟之内明白这是怎么回事.

    3. 创建你的react环境, 推荐你使用creat-react-app,我已将代码放到gitHub,所以你可以直接clone下来,感觉不错可以给我一个star. https://github.com/yurizhang/react-reduc-webpack

    二,开始

    1.我们的项目目录:

    .
    ├── src                 #开发目录
    |   |   
    |   ├──action          #action的文件
    |   |   
    |   ├──components       #展示组件
    |   |   
    |   ├──containers       #容器组件,主页
    |   |   
    |   ├──reducers         #reducer文件
    |   |
    |   |——routes           #路由文件,容器组件
    |   |
    |   |——static           #静态文件
    |   |
    |   ├──stores           #store配置文件
    |   |
    |   |
    |   └──index.js          #入口文件
    |      
    ├── build                #发布目录
    ├── node_modules        #包文件夹
    ├── .gitignore     
    ├── .jshintrc      
    
    ├── package.json        #环境配置
    └── README.md           #使用说明


    依赖的package.json
    ....
    "dependencies": {
    "axios": "^0.16.2",
    "element-react": "^1.0.19",
    "element-theme-default": "^1.3.7",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-redux": "^5.0.5",
    "redux": "^3.7.0"
    },
    
    

    三。代码文件:

    // index.js 入口文件

    import React from 'react' import ReactDOM from 'react-dom' import { createStore } from 'redux' import { Provider } from 'react-redux' //import { Button,Alert } from 'element-react'; import 'element-theme-default'; import App,{SubComponent} from './containers/app.js'; //容器组件 import counter_SubComponent from './reducers/index.js'; // reducers createStore(counter),counter_SubComponent // 生成Store const store = createStore(counter_SubComponent) ReactDOM.render( <Provider store={store}> <div> <App /> <SubComponent /> </div> </Provider>, document.getElementById('root') ) /* * `store` 由 Redux 的 `createStore(reducer)` 生成 * `state` 通过 `store.getState()` 获取,本质上一般是一个存储着整个应用状态的**对象** * `action` 本质上是一个包含 `type` 属性的普通**对象**,由 Action Creator (**函数**) 产生 * 改变 `state` 必须 `dispatch` 一个 `action` * `reducer` 本质上是根据 `action.type` 来更新 `state` 并返回 `nextState` 的**函数** * `reducer` 必须返回值,否则 `nextState` 即为 `undefined` * 实际上,**`state` 就是所有 `reducer` 返回值的汇总**(本教程只有一个 `reducer`,主要是应用场景比较简单) > Action Creator => `action` => `store.dispatch(action)` => `reducer(state, action)` => ~~`原 state`~~ `state = nextState` */

    Action

    /*
     * action cretae 这个在actionactions.js
     */
    // Action
    // export const increaseAction = { type: 'increase' }
    // export const decreaseAction = { type: 'decrease' }
    // export const subTest = { type: 'test' }
    
    export const increaseAction = (text) => {
      return { type: 'increase', text }
    }
    
    export const decreaseAction = (text) => {
      return { type: 'decrease', text }
    }
    
    export const subTest = (text) => {
      return { type: 'test', text }
    }
    
    //返回一个action对象,用来关联对应的reducer,将data保存到store。
    export const saveReducer = (data) => ({
        type: 'SAVE_REDUCER',
        data
    })

    2个显示组件

    componentsCounter.js 计数器组件

    import React, { Component } from 'react'
    import PropTypes from 'prop-types'
    
    import { Button } from 'element-react';
    
    
    
    // React component
    class Counter extends Component {
      render() {
        ////从组件的props属性中导入2个方法和一个变量
        const { value, onIncreaseClick, onDecreaseClick } = this.props;
        console.log('主组件里this.props:');
        console.log(this.props);
        return (
          <div>
            <span>{value}</span>     
            <Button type="primary" onClick={onIncreaseClick}>增加数据</Button>
            <Button type="primary" onClick={onDecreaseClick}>减少数据</Button>
            
          </div>
        )
      }
    }
    
    Counter.propTypes = {
      value: PropTypes.number.isRequired,
      onIncreaseClick: PropTypes.func.isRequired,
      onDecreaseClick: PropTypes.func.isRequired
    }
    
    export default Counter

    componentsSubComponent.js 异步加载数据组件

    import React, { Component } from 'react'
    // import PropTypes from 'prop-types'
    import { Alert, Button,Table } from 'element-react';
    
    export default class SubComponent extends Component {
        constructor(){
            super(); 
            this.state ={
               title:''
            }
        }
        componentWillMount() {        
            let id = 9999;
            this.props.getTest(id) //发送get请求,然后数据 自动写到state里
      }
    
      render() {
        console.log('另一个组件里的: this.props:');
        console.log(this.props);
        const { test="--", testData, onTest } = this.props;
        let columnName=[
          {
            label: "标题",
            prop: "title",
             180
          },
          {
            label: "年份",
            prop: "year",       
          }
        ];
        return (
            <div>        
                <Alert title={test} type="info" />
                <Button type="primary" onClick={onTest}>Change</Button> 
    
                <Table
                        style={{ '100%'}}
                        columns={columnName}
                        maxHeight={200}
                        data={testData.movies}
                />
    
            </div>     
        )
      }
    }

     容器组件 containerApp.js

    /*容器组件 */
    /* mapStateToProps, mapDispatchToProps把这个各自放到Counter和subCounter各自的组件里会不会更好? */
    import { getData} from '../plugs/fetchData'
    
    import { Message } from 'element-react';
    import { connect } from 'react-redux'
    
    import {increaseAction, decreaseAction, subTest, saveReducer} from '../action/actions.js';
    import Counter from '../components/Counter.js';  //UI组件
    import subCounter from '../components/subCounter.js'; 
    // Map Redux state to component props
    function mapStateToProps(state) {
      console.log('主容器组件里app:state:');
      console.log(state);
      return {
        value: state.counter.count,
       // test: state.SubComponent.test,
        //testData: state.SubComponent.testData
      }
    }
    //mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。
    
    // Map Redux actions to component props
    function mapDispatchToProps(dispatch) {
      return {
        onIncreaseClick: () => {
            dispatch(increaseAction());
            Message('你刚做了Add的操作');
        },  //调用Reducer
        onDecreaseClick: () => {
          dispatch(decreaseAction());
          Message('你刚做了减少的操作');
        }
      }
    }
    //如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。
    //这里建议的函数,组件可以通过 this.prop读取
    
    
    // Map Redux state to component props
    function mapSubStateToProps(state) {
      console.log('子容器组件里app:state:');
      console.log(state);
      return {
        //value: state.counter.count,
        test: state.SubComponent.test,
        testData: state.SubComponent.testData
      }
    }
    
    function mapSubCounterDispatchToProps(dispatch) {
      return {
        onTest: () => {
          dispatch(subTest());  
          Message('你刚做了subTest的操作');
        },  //调用Reducer
        getTest:(id)=> {
            try {
                getData(`/facebook/react-native/master/docs/MoviesExample.json`,{id:id}).then(response=>{
                 //axios返回的数据是用response.data包括的,和jquery不一样
                  console.log(response.data);
                  dispatch(saveReducer(response.data));
               })
                // let response = await getData(`/facebook/react-native/master/docs/MoviesExample.json?id=${id}`)
                // await dispatch(saveReducer(response.data))
            } catch (error) {
                console.log('error: ', error)
            }
          
        }
      }
    }
    
    // Connected Component
    export const SubComponent= connect(
      mapSubStateToProps,
      mapSubCounterDispatchToProps
    )(subCounter) 
    
    const App= connect(
      mapStateToProps,
      mapDispatchToProps
    )(Counter) 
    
    
    export default App
    //连接 UI组件Counter 生成一个容器组件App
    //connect方法接受两个参数:mapStateToProps和mapDispatchToProps。
    //它们定义了 UI 组件的业务逻辑。
    //前者负责输入逻辑,即将state映射到 UI 组件的参数(props), mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。
    //后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。

    recuders   recudersindex.js

    import { combineReducers } from 'redux'
    // Action
    // const increaseAction = { type: 'increase' }
    // const decreaseAction = { type: 'decrease' }
    
    // Reducer
     function counter(state = { count: 0 }, action) {
      const count = state.count
      switch (action.type) {
        case 'increase':
          return { count: count + 1 }
        case 'decrease':
          return { count: count - 1 }      
        default:
          return state
      }
    }
    
    let initState = {
        testData: [],
        test: 'default'
    }
     function SubComponent(state = initState, action) {  
      switch (action.type) {
        case 'test':
          return { ...state, test: 'test12345' }
        case 'SAVE_REDUCER':
          return {
              ...state,
              testData: action.data
          }      
        default:
          return state
      }
    }
    
    //以后的业务里 这些reducers拆分成多个,这里分别导入进来
    
    const counter_SubComponent = combineReducers({
      counter,
      SubComponent
    })
    
    export default counter_SubComponent;
    //合并reducers让 const store = createStore(counter_SubComponent)生成一个状态

    封装一些插件

    plugsfetchData.js

    import axios from 'axios'
    //BASE_URL是默认的url地址,如果你安装了webpack,可以在webpack配置全局变量
    //axios.defaults.baseURL = BASE_URL;
    
    //如果没有安装webpack,就使用下面这种写法
    axios.defaults.baseURL = "https://raw.githubusercontent.com/"
    
    
    export const getData = (url, param) => {
        return (
            axios.get(`${url}`, {params:param})
        );
    }
    
    export const postData = (url, param) => {
        return (
            axios.post(`${url}`, param)
        );
    }

    先RUN起来,后面我们来一个一个告诉这些代码是什么意思 

     
    这样的一片黑是什么东西?
  • 相关阅读:
    声明
    Random类——获取随机数
    JDK_API的使用方法
    Ajax?有谁开始学习了吗?
    用xslt循环xml同一节点的不同子节点
    在Repeater控件中嵌套一个Repeater控件
    html+css的一些技巧.收集中...
    记录一下: onbeforeunload()方法, 避免未保存而关闭页面.
    简单的C# Socket编程
    不实用的UriBuilder类
  • 原文地址:https://www.cnblogs.com/yuri2016/p/7204594.html
Copyright © 2020-2023  润新知