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 這個在action\actions.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個顯示組件

components\Counter.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

 

components\SubComponent.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",
        width: 180
      },
      {
        label: "年份",
        prop: "year",       
      }
    ];
    return (
        <div>        
            <Alert title={test} type="info" />
            <Button type="primary" onClick={onTest}>Change</Button> 

            <Table
                    style={{width: '100%'}}
                    columns={columnName}
                    maxHeight={200}
                    data={testData.movies}
            />

        </div>     
    )
  }
}

 

 容器組件 container\App.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   recuders\index.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)生成一個狀態

 

封裝一些插件

plugs\fetchData.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起來,后面我們來一個一個告訴這些代碼是什么意思 

 

 

 
這樣的一片黑是什么東西?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM