React Project : Step 10 Redux

在index中加入redux dev-tools

在这里插入图片描述

import burgerBulderReducer from './store/reducers/burgerBuilder';


const store =createStore(burgerBulderReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

将Action转为Action Creators

在这里插入图片描述
将store中的reducer和action分为actions和reucers;
burgerBuilder.js
存放ingredients的加减action creators;

import * as actionTypes from './actionsTypes';

export const addIngredient = (name)=>{            //转为action creator
    return {
        type:actionTypes.ADD_INGREDIENTS,
        ingredientName: name
    };
};

export const removeIngredient = (name)=>{
    return {
        type:actionTypes.REMOVE_INGREDIENTS,
        ingredientName:name
    };
};

index.js
将所有需要export的action creator在此export;

export {addIngredient, removeIngredient} from './burgerBuilder';
export {} from './order';

在BurgerBuilder.js中的dispatch中,调用此action creator

import * as burgerBuilderActions from '../../store/actions/index';
const mapDispatchToProps=dispatch=>{
    return{
        onIngredientAdded:(ingName)=>dispatch(burgerBuilderActions.addIngredient(ingName)),
        onIngredientRemoved:(ingName)=>dispatch(burgerBuilderActions.removeIngredient(ingName))
    };
};

由此——同步的actions已转为actioncreators

为action添加异步操作

将dev-tools调整为advanced mode

在这里插入图片描述

import {createStore,applyMiddleware, compose} from 'redux';
import thunk from 'redux-thunk';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store =createStore(burgerBulderReducer, composeEnhancers(
     applyMiddleware(thunk)
));

在componentdidmount中调用异步请求

BurgerBuilder——get请求

actionType中建立两个新的actiontypes

export const ADD_INGREDIENTS = 'ADD_INGREDIENTS';
export const REMOVE_INGREDIENTS='REMOVE_INGREDIENTS';
export const SET_INGREDIENTS = 'SET_INGREDIENTS';
export const FETCH_INGREDIENTS_FAILED='FETCH_INGREDIENTS_FAILED';

reducer中设置这两个type的case
第一个将ingredients放入state;
第二个将state中的error变为true,说明请求失败;

case actionTypes.SET_INGREDIENTS:
            return {
                ...state,
                ingredients:action.ingredients,
                error:false
            };
case actionTypes.FETCH_INGREDIENTS_FAILED:
            return {
                ...state,
                error:true
            };

设置请求的action creator
同步函数+异步函数(middleware辅助);
在axiosget成功后进行dispatch;
若失败则也dispatch;

export const setIngredients =(ingredients)=>{
    return {
        type:actionTypes.SET_INGREDIENTS,
        ingredients:ingredients
    };
};

export const initIngredients=()=>{
    return (dispatch)=>{           //thunk使得dispatch可被传入
        axios.get( '/ingredients.json' )
        .then( response => {
            dispatch(setIngredients(response.data));
        } )
        .catch( error => {
            dispatch(fetchingredientsfailed());
        } );
    };
};

最后在BurgerBuilder的didimount中调用此异步函数

    componentDidMount () {   //用于从database抓取初始ingredient
        this.props.onInitIngredients();
    }

Order & Checkout——post请求

actionTypes.js
success用与异步action的调用;
start用于判断异步时loading的状态;

export const ADD_INGREDIENTS = 'ADD_INGREDIENTS';
export const REMOVE_INGREDIENTS='REMOVE_INGREDIENTS';
export const SET_INGREDIENTS = 'SET_INGREDIENTS';
export const FETCH_INGREDIENTS_FAILED='FETCH_INGREDIENTS_FAILED';

export const PURCHASE_BURGER_SUCCESS = 'PURCHASE_BURGER_SUCCESS';
export const PURCHASE_BURGER_FAIL = 'PURCHASE_BURGER_FAIL';

//控制loading
export const PURCAHSE_BURGER_START ='PURCAHSE_BURGER_START';

Order——action creator
成功,失败,开始都在异步中被调用;
reducer中设置同步action的case;

import * as actionType from './actionsTypes';
import axios from '../../axios-orders';

export const purchaseBurgerSuccess =(id, orderData)=>{
    return {
        type:actionType.PURCHASE_BURGER_SUCCESS,
        orderId:id,
        orderData:orderData
    };
};

export const purchaseBurgerFail = (error)=>{
    return {
        type:actionType.PURCHASE_BURGER_FAIL,
        error:error
    };
};

export const purchaseBurgerStart=()=>{        //用于在reducer中控制loading状态
    return {
        type:actionType.PURCAHSE_BURGER_START
    }
}

//async        不返回一个action,返回一个调用action的异步函数
export const purchaseBurger = (orderData) => {        
    return dispatch=>{
        dispatch(purchaseBurgerStart());//在异步调用前改变loading——要用dispatch包裹
        axios.post( '/orders.json', orderData )
        .then( response => {
            console.log(response.data);  //name才是真正的id
            dispatch(purchaseBurgerSuccess(response.data.name,orderData));
        } )
        .catch( error => {
            dispatch(purchaseBurgerFail(error));
        } );
    };
};


Order——reducer
成功则改变状态;
失败则保持状态;
开始则改变laoding状态;

import * as actionTypes from '../actions/actionsTypes';
const initialState={
    orders: [],
    loading: false
};

const reducer = (state=initialState, action)=>{
    switch(action.type){
        case actionTypes.PURCHASE_BURGER_SUCCESS:
            const newOrder ={
                ...action.orderData,
                id:action.orderId
            };
            return{
                ...state,
                loading: false,
                orders: state.orders.concat(newOrder)
            };
        case actionTypes.PURCHASE_BURGER_FAIL:
            return{
                ...state,
                loading:false         //不改变state,用witherror获取error
            };
        case actionTypes.PURCAHSE_BURGER_START:
            return{
                ...state,
                loading:true
            };
        default:
            return state;
    }
};

export default reducer;

放入checkout和contactdata中

import * as actions from '../../store/actions/index';

提交表单——处理order,传入异步action

orderHandler=(event)=>{ //接受点击事件
        const formData = {};
        for(let formElementIdentifier in this.state.orderForm){
            formData[formElementIdentifier] = this.state.orderForm[formElementIdentifier].value;
        };

        const order = {
            ingredients: this.props.ings,
            price: this.props.price,
            orderData:formData
        }

        this.props.onOrderBurger(order);  //调用action

        event.preventDefault();  //阻止页面刷新
    }

error可用witherrorhandler捕获,传入reducer的状态和action;

const mapStateToProps = state=>{
    return{
        ings:state.burgerBuilder.ingredients,
        price:state.burgerBuilder.totalPrice,
        loading:state.order.loading
    }
};

const mapDispatchToProps = dispatch=>{
    return{
        onOrderBurger:(orderData)=>dispatch(actions.purchaseBurger(orderData))
    };
}

export default connect(mapStateToProps,mapDispatchToProps)(withErrorHandler(ContactData,axios));

将两个reducer合体——再index.js中

用到 combineReducers from ‘redux’

import React, { createContext } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import {BrowserRouter} from 'react-router-dom';

import {Provider} from 'react-redux';
import {createStore,applyMiddleware, compose, combineReducers} from 'redux';

import thunk from 'redux-thunk';

import burgerBulderReducer from './store/reducers/burgerBuilder';
import orderReducer from './store/reducers/order';


const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const rootReducer=combineReducers({
     burgerBuilder:burgerBulderReducer,
     order:orderReducer
});

const store =createStore(rootReducer, composeEnhancers(
     applyMiddleware(thunk)
));

ReactDOM.render(
<Provider store = {store}>
     <BrowserRouter>
          <App />
     </BrowserRouter>
</Provider>
, document.getElementById('root'));
registerServiceWorker();

调用state.burgerbuiilder.statename或state.order.statename

Bug——提交后重定向+重置价格

重定向——BurgerBuilder.js中
按下continue后就将purchased定位false;
在进入checkout页面之前,将state转为false;

    purchaseContinueHandler = () => {            //重定位在这里
        this.props.onInitPurchase();
        this.props.history.push('/checkout');
    }
const mapDispatchToProps=dispatch=>{
    return{
        onIngredientAdded:(ingName)=>dispatch(Actions.addIngredient(ingName)),
        onIngredientRemoved:(ingName)=>dispatch(Actions.removeIngredient(ingName)),
        onInitIngredients:()=>dispatch(Actions.initIngredients()),
        onInitPurchase: ()=>dispatch(Actions.purchaseInit())
    };
};

若将函数放在checkout的 willmount中,不能阻止一开始render true状态,依旧会重定向到’/’;
所以需要放在checkout的前一个component中,在进入checkoutcomponent之前将state 变为false;

Price重置

        case actionTypes.SET_INGREDIENTS:
            return {
                ...state,
                ingredients:action.ingredients,
                error:false,
                totalPrice:3.7
            };

actions由action中的inedx.js集中存放

reducers由combineReducers合并

用redux调用order界面

与一开始getingredients基本相同
异步分为success,failed,start三个同步action;

export const FETCH_ORDERS_START = 'FETCH_ORDERS_START';
export const FETCH_ORDERS_SUCCESS = 'FETCH_ORDERS_SUCCESS';
export const FETCH_ORDERS_FAIL = 'FETCH_ORDERS_FAIL';

同步+异步action
先start,then(success),catch(failed)

//orders  success+fail+asych
export const fetchOrdersSuccess=(orders)=>{
    return {
        type:actionType.FETCH_ORDERS_SUCCESS,
        orders:orders
    };
};

export const fetchOrdersFailed=(error)=>{
    return {
        type:actionType.FETCH_ORDERS_FAIL,
        error:error
    };
};

export const fetchOrdersStart=()=>{
    return{
        type:actionType.FETCH_ORDERS_START
    };
};

export const fetchOrders= ()=>(dispatch)=>{       //actioncreator函数——返回一个action
        dispatch(fetchOrdersStart());
        axios.get('/orders.json')
            .then(res=>{
                const fetchOrders=[];
                for(let key in res.data){
                    fetchOrders.push({
                        ...res.data[key],
                        id:key
                    });
                }
                dispatch(fetchOrdersSuccess(fetchOrders));
            })
            .catch(error=>{
                dispatch(fetchOrdersFailed(error));
            });
};

在reducer中添加三个case

            };
        case actionTypes.FETCH_ORDERS_START:
            return{
                ...state,
                loading:true         //一个参数用多个页面
            };
        case actionTypes.FETCH_ORDERS_SUCCESS:
            return{
                ...state,
                orders:action.orders,
                loading:false
            };
        case actionTypes.FETCH_ORDERS_FAIL:
            return {
                ...state,
                loading:false
            }

将异步action放入orders.js中
connect传入state和action;
spinner配合条件判断,在start和success中间显示spinner;

import React, { Component } from 'react';
import Order from '../../components/order/Order';
import axios from '../../axios-orders';
import withErrorHandler from '../../hoc/withErrorHandler/withErrorHandler';

import * as actions from '../../store/actions/index';     //index可省略
import {connect} from 'react-redux';
import Spinner from '../../components/UI/Spinner/Spinner';

class Orders extends Component{
    //fetch all orders
    componentDidMount(){
        this.props.onFetchOrders();
    };

    render(){
        let order = <Spinner/>;
        if(!this.props.loading){
            order=(
                this.props.orders.map((order)=>(
                <Order 
                    key ={order.id}
                    ingredients={order.ingredients}
                    price={order.price}
                />
                )
                ));
        };
        return(
            <div>
                {order}
            </div>
        );
    };
};
const mapStateToProps = state=>{
    return{ 
        orders:state.order.orders,
        loading: state.order.loading
    };
};
const mapDispatchToProps = dispatch => {
    return {
        onFetchOrders: ()=>dispatch(actions.fetchOrders())
    };
};
export default connect(mapStateToProps,mapDispatchToProps)(withErrorHandler(Orders, axios));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值