react-router + redux + react-redux 的例子與分析

一個 react-router + redux  + react-redux 的例子與分析

index.js 

import React from 'react'
import ReactDom from 'react-dom'
import App from './App'
ReactDom.render(
    <App/>,
    document.getElementById('root')
)

沒什麼好說的react

 

App.js : 

import React from 'react'
import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import reducers from './reducers'
import RouterMap from './router'
let store = createStore(reducers, applyMiddleware(thunk))
const App = () => {
    return (
        <Provider store={ store }>
            <RouterMap/>
        </Provider>
    )
}
export default App

 

代碼分析:ios

  1. reducers: redux 中的 reducers
  2. thunk: 異步action 的插件
  3. applyMiddleware: react 的中間件,用於添加插件
  4. RouterMap: 路由配置
  5. Provider:讓全部容器組件均可以訪問 store
  6. createStore: redux 生成 store 的方法

 

例子中的:RouterMap

import React from 'react'
// react-router 相關
import { Router, Route, Switch } from 'react-router-dom'
// 瀏覽器的History模式
import createHistory from 'history/createBrowserHistory'
// 生成一個redux容器的方法
import { connect } from 'react-redux'
// 一個action
import { initCity } from '../actions/userinfo'
// 組件
import Home from '../containers/Home'
import City from '../containers/City'
// 建立 history
const history = createHistory()

class App extends React.Component {
    render() {
        return (
            <Router history={ history }>
                <Switch>
                    <Route exact path="/" component={ Home }></Route>
                    <Route path="/city" component={ City }></Route>
                </Switch>
            </Router>
        )
    }
    componentDidMount() {
        this.props.initCity(cityName)
    }
}
function mapStateToProps(state) {
    return {
        userInfo: state.userInfo
    }
}
function mapDispatchToProps(dispatch, ownprops) {
    return {
        initCity: (cityName) => {
        }
    }
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App)

 

代碼分析:ajax

  • connect:
  1. 該方法接受2個參數,返回一個函數,返回的函數的參數一般 是react 組件,例子是App
  2. 參數1是函數,函數接收 store 中的 state 做爲參數,一般 返回 state 中的數據,例子中的App組件能夠經過 this.props.userInfo 獲取數據
  3. 參數2是函數,函數接收 store 中的 dispatch做爲第一個參數,一般返回提交action的一些方法,例子中的App組件能夠經過 this.props.initCity(cityName) 提交action
  • <Router history={ history }> : 傳遞history 給全部組件,組件就能夠經過 this.props.history.push('路由')跳轉頁面, this.props.history.goBack() 方法返回
  • <Route path="/city" component={ City }></Route> : 路由配置  

 

例子中的:reducers

import { combineReducers } from 'redux'

export function detailInfo(state = {}, action) {
    switch (action.type) {
        case 'GET_DETAIL_INFO':
            return {
                ...state,
                info: action.payload.info
            }
        case 'GET_COMMENT_LIST':
            return {
                ...state,
                comments: action.payload.comments
            }
        default: 
            return state
    }
}

const initialState = {page: 0, likeList: [] }
export function userInfo(state = initialState, action) {
    switch (action.type) {
        case 'USER_CURRENTCITY':
            return {
                ...state,
                cityName: action.payload.cityName,
                userName: '小名'
            }
        case 'SAVE_HOMEAD':
            return {
                ...state,
                homeAd: action.payload.homeAd
            }
        case 'SAVE_LIKELIST': 
            return {
                ...state,
                page: state.page + 1,
                likeList: state.likeList.concat(action.payload.likeList)
            }
        case 'SET_ISLOADINGLIKELIST_FLAG':
            return {
                ...state,
                isLoading: action.payload.isLoading
            }
        default:
            return state
    }
}

export  default combineReducers({
    userInfo,
    detailInfo
})

 

代碼分析:combineReducers: 接收一個拆分後 reducer 函數組成的對象,返回一個新的 Reducer 函數redux

 

 

代碼中的:全部action ,案例只列舉:initCity 

import axois from 'axios'

export function getDetailInfo(shopId) {
    return dispatch => axois.get(`/api/detail/info/${shopId}`).then((res) => {
        dispatch(saveDetailInfo(res.data))
    }).catch((error) => {
        console.log(error)
    })
}
export function saveDetailInfo(res) {
    return {
        type: 'GET_DETAIL_INFO',
        payload: {
            info: res
        }
    }
}

export function getComments(shopId) {
    return axois.get(`/api/detail/comment/${shopId}`).then((res) => {
        dispatch(saveComments(res.data))
    }).catch((error) => {
        console.log(error)
    })
}
export function saveComments(res) {
    return {
        type: 'GET_COMMENT_LIST',
        payload: {
            comments: res
        }
    }
}

 

  1. axois: ajax請求的插件
  2. getDetailInfo:
  • 該action 返回了一個發送ajax異步請求的函數
  • 異步請求成功後 觸發一個action :  dispatch(saveDetailInfo(res.data))
  • 普通的action 一般返回一個對象,它之因此可以返回函數,是因爲利用了插件「thunk'」,這個是異步action 的寫法

 

 

City

import React from 'react'
import { connect } from 'react-redux'
import { updateCity } from '../../actions/userinfo'
import Header from '../../components/Header'
import CityList from '../../components/CityList'
import CurrentCity from './subpages/CurrentCity'

class City extends React.Component {
    render() {
        return (
            <div>
                <Header title="選擇城市" goBack={ this.goBack.bind(this) }></Header>
                <CurrentCity currentCityName={ this.props.userInfo.cityName }></CurrentCity>
                <CityList chooseCity= { this.chooseCity.bind(this) }></CityList>
            </div>
        )
    }
    goBack() {
        this.props.history.goBack()
    }
    chooseCity(cityName) {
        localStore.setItem('USER_CURRENT_CITY', cityName)
        this.props.initCity(cityName)
        this.props.history.goBack()
    }
}

function mapStateToProps(state) {
    return {
        userInfo: state.userInfo
    }
}
function mapDispatchToProps(dispatch, ownProps) {
    return {
        initCity: (cityName) => {
            dispatch(updateCity(cityName))
        }
    }
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(City)

 

goBack={ this.goBack.bind(this) } : 將組件自己的goBack方法,傳遞給 Header 組件 , bind的做用是:在Header組件調用該方法時,上下文爲City組件的 thisaxios

 

 

 

Header

import React from 'react'
class Header extends React.Component {
    render() {
        return (
            <div id="common-header">
                <span className="back-icon" onClick={ this.clickHandle.bind(this) }>
                    <i className="icon-chevron-left"></i>
                </span>
                <h1>{ this.props.title }</h1>
            </div>
        )
    }
    clickHandle() {
        window.history.back()
    }
}
export default Header

 

Header組件並無用connect包裝,由於它是純顯示的組件,只有跟業務相關的組件,纔會用connect容器包裝api

相關文章
相關標籤/搜索