react项目使用redux入门-6-redux-thunk中间件处理异步请求(The react project uses the Redux starter-6-redux thunk middleware to handle asynchronous requests)-react
react项目使用redux入门-6-redux-thunk中间件处理异步请求(The react project uses the Redux starter-6-redux thunk middleware to handle asynchronous requests)
场景:切换语言、请求产品列表
-
src/index.tsx
import React from ‘react’
import ReactDOM from ‘react-dom’
import { Provider } from ‘react-redux’ // react-redux 利用上下文context,提供的数据组件Provider
import ‘antd/dist/antd.css’
import ‘./index.css’
import App from ‘./App’
import ‘i18n’import store from ‘redux/store’
ReactDOM.render(
,
{/* 使用Provider, 并加载 数据仓库 store, 就可以在全局范围内使用store */}
document.getElementById(‘root’)
) -
ListPage组件中请求数据
import { Component } from ‘react’
import { connect } from ‘react-redux’
import { ThunkDispatch } from ‘redux-thunk’ // ThunkDispatch为了支持函数类型的action,提供dispatch的类型
import { RootState } from ‘redux/store’
import { ActionsProductProps, fetchProductsActionCreator } from ‘redux/product/actions’const mapStateToProps = ({ product }) => product
// const mapStateToProps = ({ product }: RootState) => {
// return {
// loading: product.loading,
// productList: product.productList
// }
// }const mapDispatchToProps = (dispatch: ThunkDispatch
) => {
fetchProduct : () => dispatch(fetchProductsActionCreator())
}class ListPageComponent extends Component
& ReturnType , any> { componentDidMount() {
const { fetchProduct } = this.props
fetchProduct()
}render(){
const { productList, loading } = this.props
return loading?正在加载……🙁
{
productList.map(item =>{item.name}
)
})
}
}
export const ListPage = connect(mapStateToProps, mapDispatchToProps)(ListPageComponent) -
Header组件中使用
import { Component } from ‘react’
import { withRouter, RouteComponentProps } from ‘react-router-dom’
import { MenuInfo } from ‘rc-menu/lib/interface’
import { nanoid } from ‘nanoid’
// 使用react-redux
import { Dispatch } from ‘redux’
import { connect } from ‘react-redux’
import store, { RootState } from ‘redux/store’
import { addLanguageActionCreator, changeLanguageActionCreator } from ‘redux/language/actionCreators’const mapStateToProps = (state: RootState) => {
return {
lng: state.language.lng,
languageList: state.language.languageList
}
}const mapDispatchToProps = (dispatch: Dispatch) => {
return {
addLanguageDispatch: (language: { code: string, language: string }) => {
dispatch(addLanguageActionCreator(language))
}
changeLanguageDispatch: (lng: ‘en’|’zh’) => {
dispatch(changeLanguageActionCreator(lng))
}
}
}class HeaderComponent extends Component
& ReturnType >{
render(){
const { history, lng, languageList, addLanguageDispatch, changeLanguageDispatch } = this.props/* meun 的点击事件 */
const oprateLanguage = ( e: MenuInfo ) => {
if(e.key !== ‘new’){
changeLanguageDispatch(e.key)
}else{
addLanguageDispatch({code: `lng${nanoid()}`, language: ‘新语种’})
}
}const menu = (
)return (
让旅游更幸福
)
}
}export const Header = connect(mapStateToProps, mapDispatchToProps)(withRouter(HeaderComponent))
-
store数据封装
新建目录:src/redux、src/redux/language
新建文件:src/redux/store.ts、src/redux/language/actionCreators.ts,src/redux/language/reducers.tsmkdir src/redux src/redux/language
touch src/redux/language/actionCreators.ts src/redux/language/reducer.ts
touch src/redux/product/actions.ts src/redux/product/reducer.tsstore.ts
import { createStore, combineReducers, applyMiddleware } from ‘redux’
import languageReducer form ‘./language/reducer.ts’
import productReducer form ‘./product/reducer.ts’
import thunk form ‘redux-thunk’// 使用 combineReducers方法,连接多个reducer
const rootReducer = combineReducers({
language: languageReducer,
product: productReducer
})// redux-thunk 使用thunk中间件,使得redux的action除了对象形式,还是支持函数类型
const store = createStore(rootReducer, applyMiddleware(thunk))// 使用ts的条件类型 ReturnType
,T:函数类型。 获取函数返回值的类型
export type RootState = ReturnTypeexport default store
product:- product/actions.ts、product/reducers.ts
actions.ts
// 使用redux-thunk,支持函数类型的action,这个action的类型:ThunkAction
import { ThunkAction } from ‘react-thunk’
import axios from ‘axios’
import { RootState } from ‘redux/store’// fetch_start 主要是用来控制loading, 开始发接口,loading值为true
export const FETCH_START = ‘product/fetch_start’
// fetch_success 主要用来 接口数据成功,将数据data存入store
export const FETCH_SUCCESS = ‘product/fetch_success’
export const FETCH_FAIL = ‘product/fetch_fail’interface ActionFetchStartProps { type: typeof FETCH_START}
interface ActionFetchSuccessProps { type: typeof FETCH_SUCCESS, payload: any}
interface ActionFetchFailProps { type: typeof FETCH_FAIL }
export type ActionsProductProps = ActionFetchStartProps | ActionFetchSuccessProps | ActionFetchFailProps// actionCreator
export const fetchStartActionCreator = (): ActionFetchStartProps => ({ type: FETCH_START})
export const fetchSuccessActionCreator = (data:any):ActionFetchSuccessProps => ({ type: FETCH_SUCCESS, payload: data })
export const fetchFailActionCreator = ():ActionFetchFailProps => ({ type: FETCH_FAIL })// 函数类型的action
export const fetchProductsActionCreator = (): ThunkAction=> async (dispatch, getState) => {
dispactch(fetchStartActionCreator())
try{
const { data } = await axios.get(‘/api/products’)
dispatch(fetchSuccessActionCreator(data))
}catch{
dispatch(fetchFailActionCreator())
}
}reducer.ts
import { ActionsProductProps, FETCH_START, FETCH_SUCCESS, FETCH_FAIL } from ‘./actions.ts’
interface ProductState {
loading: boolean,
productList: any[]
}
const defaultState: ProductState = {
loading: false,
productList: []
}
export default (state = defaultState, action:ActionsProductProps ) => {
switch (action.type) {
case FETCH_START:
return { …state, loading: true }
case FETCH_SUCCESS:
return { …state, loading: false, tourists: action.payload }
case FETCH_FAIL:
return { …state, loading: false }
default:
return state
}
}language:- language/actions.ts、language/reducers.ts
actions.ts
/* 用常量定义action.type,减少代码敲错 */
export const ADD_LANGUAGE = ‘language/add’
export const CHANGE_LANGUAGE = ‘language/change’/* action的类型申明 */
const AddActionProps = {
type: typeof ADD_LANGUAGE,
payload: { code: string, language: string }
}
const ChangeActionProps = {
type: typeof CHANGE_LANGUAGE,
payload: ‘zh’ | ‘en’
}export type LanguageActionProps = AddActionProps | ChangeActionProps
/* 用工厂模式创建action */
export const addLanguageActionCreator = (language: {code: string, language: string}):ADD_LANGUAGE => {
return {
type: ADD_LANGUAGE,
payload: language
}
}
export const changeLanguageActionCreator = (lng: ‘zh’ | ‘en’):CHANGE_LANGUAGE => {
return {
type: CHANGE_LANGUAGE,
payload: lng
}
}2. `reducer.ts`
import { ADD_LANGUAGE, CHANGE_LANGUAGE, LanguageActionProps } from ‘./actions’
export interface LanguageState {
lng: ‘zh’ | ‘en’,
languageList: {code: string, language: string}[]
}const defaultStoreState: LanguageState = {
lng: ‘zh’,
languageList: [{ code: ‘zh’, language: ‘中文’}, { code: ‘en’, language: ‘English’}]
}export default (state = defaultStoreState, action:LanguageActionProps) => {
switch (action.type) {
case CHANGE_LANGUAGE:
return { …state, lng: action.payload }
case ADD_LANGUAGE:
return { …state, languageList: […state.languageList, action.payload] }
default:
return state
}
} - 新建目录:src/redux、src/redux/language
- 新建文件:src/redux/store.ts、src/redux/language/actionCreators.ts,src/redux/language/reducers.ts
- store.ts
- product:- product/actions.ts、product/reducers.ts
- actions.ts
- reducer.ts
- language:- language/actions.ts、language/reducers.ts
- actions.ts
Scenario: switching languages and requesting product lists
-
src/index.tsx
import React from ‘react’
import ReactDOM from ‘react-dom’
import { Provider } from ‘react-redux’ // react-redux 利用上下文context,提供的数据组件Provider
import ‘antd/dist/antd.css’
import ‘./index.css’
import App from ‘./App’
import ‘i18n’import store from ‘redux/store’
ReactDOM.render(
,
{/* 使用Provider, 并加载 数据仓库 store, 就可以在全局范围内使用store */}
document.getElementById(‘root’)
) -
ListPage组件中请求数据
import { Component } from ‘react’
import { connect } from ‘react-redux’
import { ThunkDispatch } from ‘redux-thunk’ // ThunkDispatch为了支持函数类型的action,提供dispatch的类型
import { RootState } from ‘redux/store’
import { ActionsProductProps, fetchProductsActionCreator } from ‘redux/product/actions’const mapStateToProps = ({ product }) => product
// const mapStateToProps = ({ product }: RootState) => {
// return {
// loading: product.loading,
// productList: product.productList
// }
// }const mapDispatchToProps = (dispatch: ThunkDispatch
) => {
fetchProduct : () => dispatch(fetchProductsActionCreator())
}class ListPageComponent extends Component
& ReturnType , any> { componentDidMount() {
const { fetchProduct } = this.props
fetchProduct()
}render(){
const { productList, loading } = this.props
return loading?正在加载……🙁
{
productList.map(item =>{item.name}
)
})
}
}
export const ListPage = connect(mapStateToProps, mapDispatchToProps)(ListPageComponent) -
Header组件中使用
import { Component } from ‘react’
import { withRouter, RouteComponentProps } from ‘react-router-dom’
import { MenuInfo } from ‘rc-menu/lib/interface’
import { nanoid } from ‘nanoid’
// 使用react-redux
import { Dispatch } from ‘redux’
import { connect } from ‘react-redux’
import store, { RootState } from ‘redux/store’
import { addLanguageActionCreator, changeLanguageActionCreator } from ‘redux/language/actionCreators’const mapStateToProps = (state: RootState) => {
return {
lng: state.language.lng,
languageList: state.language.languageList
}
}const mapDispatchToProps = (dispatch: Dispatch) => {
return {
addLanguageDispatch: (language: { code: string, language: string }) => {
dispatch(addLanguageActionCreator(language))
}
changeLanguageDispatch: (lng: ‘en’|’zh’) => {
dispatch(changeLanguageActionCreator(lng))
}
}
}class HeaderComponent extends Component
& ReturnType >{
render(){
const { history, lng, languageList, addLanguageDispatch, changeLanguageDispatch } = this.props/* meun 的点击事件 */
const oprateLanguage = ( e: MenuInfo ) => {
if(e.key !== ‘new’){
changeLanguageDispatch(e.key)
}else{
addLanguageDispatch({code: `lng${nanoid()}`, language: ‘新语种’})
}
}const menu = (
)return (
让旅游更幸福
)
}
}export const Header = connect(mapStateToProps, mapDispatchToProps)(withRouter(HeaderComponent))
-
store数据封装
新建目录:src/redux、src/redux/language
新建文件:src/redux/store.ts、src/redux/language/actionCreators.ts,src/redux/language/reducers.tsmkdir src/redux src/redux/language
touch src/redux/language/actionCreators.ts src/redux/language/reducer.ts
touch src/redux/product/actions.ts src/redux/product/reducer.tsstore.ts
import { createStore, combineReducers, applyMiddleware } from ‘redux’
import languageReducer form ‘./language/reducer.ts’
import productReducer form ‘./product/reducer.ts’
import thunk form ‘redux-thunk’// 使用 combineReducers方法,连接多个reducer
const rootReducer = combineReducers({
language: languageReducer,
product: productReducer
})// redux-thunk 使用thunk中间件,使得redux的action除了对象形式,还是支持函数类型
const store = createStore(rootReducer, applyMiddleware(thunk))// 使用ts的条件类型 ReturnType
,T:函数类型。 获取函数返回值的类型
export type RootState = ReturnTypeexport default store
product:- product/actions.ts、product/reducers.ts
actions.ts
// 使用redux-thunk,支持函数类型的action,这个action的类型:ThunkAction
import { ThunkAction } from ‘react-thunk’
import axios from ‘axios’
import { RootState } from ‘redux/store’// fetch_start 主要是用来控制loading, 开始发接口,loading值为true
export const FETCH_START = ‘product/fetch_start’
// fetch_success 主要用来 接口数据成功,将数据data存入store
export const FETCH_SUCCESS = ‘product/fetch_success’
export const FETCH_FAIL = ‘product/fetch_fail’interface ActionFetchStartProps { type: typeof FETCH_START}
interface ActionFetchSuccessProps { type: typeof FETCH_SUCCESS, payload: any}
interface ActionFetchFailProps { type: typeof FETCH_FAIL }
export type ActionsProductProps = ActionFetchStartProps | ActionFetchSuccessProps | ActionFetchFailProps// actionCreator
export const fetchStartActionCreator = (): ActionFetchStartProps => ({ type: FETCH_START})
export const fetchSuccessActionCreator = (data:any):ActionFetchSuccessProps => ({ type: FETCH_SUCCESS, payload: data })
export const fetchFailActionCreator = ():ActionFetchFailProps => ({ type: FETCH_FAIL })// 函数类型的action
export const fetchProductsActionCreator = (): ThunkAction=> async (dispatch, getState) => {
dispactch(fetchStartActionCreator())
try{
const { data } = await axios.get(‘/api/products’)
dispatch(fetchSuccessActionCreator(data))
}catch{
dispatch(fetchFailActionCreator())
}
}reducer.ts
import { ActionsProductProps, FETCH_START, FETCH_SUCCESS, FETCH_FAIL } from ‘./actions.ts’
interface ProductState {
loading: boolean,
productList: any[]
}
const defaultState: ProductState = {
loading: false,
productList: []
}
export default (state = defaultState, action:ActionsProductProps ) => {
switch (action.type) {
case FETCH_START:
return { …state, loading: true }
case FETCH_SUCCESS:
return { …state, loading: false, tourists: action.payload }
case FETCH_FAIL:
return { …state, loading: false }
default:
return state
}
}language:- language/actions.ts、language/reducers.ts
actions.ts
/* 用常量定义action.type,减少代码敲错 */
export const ADD_LANGUAGE = ‘language/add’
export const CHANGE_LANGUAGE = ‘language/change’/* action的类型申明 */
const AddActionProps = {
type: typeof ADD_LANGUAGE,
payload: { code: string, language: string }
}
const ChangeActionProps = {
type: typeof CHANGE_LANGUAGE,
payload: ‘zh’ | ‘en’
}export type LanguageActionProps = AddActionProps | ChangeActionProps
/* 用工厂模式创建action */
export const addLanguageActionCreator = (language: {code: string, language: string}):ADD_LANGUAGE => {
return {
type: ADD_LANGUAGE,
payload: language
}
}
export const changeLanguageActionCreator = (lng: ‘zh’ | ‘en’):CHANGE_LANGUAGE => {
return {
type: CHANGE_LANGUAGE,
payload: lng
}
}2. `reducer.ts`
import { ADD_LANGUAGE, CHANGE_LANGUAGE, LanguageActionProps } from ‘./actions’
export interface LanguageState {
lng: ‘zh’ | ‘en’,
languageList: {code: string, language: string}[]
}const defaultStoreState: LanguageState = {
lng: ‘zh’,
languageList: [{ code: ‘zh’, language: ‘中文’}, { code: ‘en’, language: ‘English’}]
}export default (state = defaultStoreState, action:LanguageActionProps) => {
switch (action.type) {
case CHANGE_LANGUAGE:
return { …state, lng: action.payload }
case ADD_LANGUAGE:
return { …state, languageList: […state.languageList, action.payload] }
default:
return state
}
} - 新建目录:src/redux、src/redux/language
- 新建文件:src/redux/store.ts、src/redux/language/actionCreators.ts,src/redux/language/reducers.ts
- store.ts
- product:- product/actions.ts、product/reducers.ts
- actions.ts
- reducer.ts
- language:- language/actions.ts、language/reducers.ts
- actions.ts