Redux 用于存放ingredients和prices(全局调用的state)
index.js
Provider需要包裹所有的东西;
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} from 'redux';
import reducer from './store/reducer';
const store =createStore(reducer);
ReactDOM.render(
<Provider store = {store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'));
registerServiceWorker();
reducer.js
先不用异步操作请求http,初始化ingredients先;
设置函数改变ingredients;
为改变price,需要加入每个ingredients的价格列表,在add和remove时进行加减;
import * as actionTypes from './actions';
const initialState ={ //定义价格
ingredients: {
salad:0,
bacon:0,
cheese:0,
meat:0
},
totalPrice: 3.7
};
const INGREDIENT_PRICES = {
salad: 0.5,
cheese: 0.4,
meat: 1.3,
bacon: 0.7
};
const reducer = (state=initialState,action)=>{
switch(action.type){
case actionTypes.ADD_INGREDIENTS:
return {
...state,
ingredients:{
...state.ingredients,
[action.ingredientName]:state.ingredients[action.ingredientName]+1
//【】可存放代码
},
totalPrice:state.totalPrice+INGREDIENT_PRICES[action.ingredientName]
};
case actionTypes.REMOVE_INGREDIENTS:
return {
...state,
ingredients:{
...state.ingredients,
[action.ingredientName]:state.ingredients[action.ingredientName]-1
},
totalPrice:state.totalPrice-INGREDIENT_PRICES[action.ingredientName]
};
default:
return state;
}
};
export default reducer;
export default reducer;
BurgerBuilder.js
去掉与ingredients和price有关的state内容;
使用connect将witherror等包裹;
传入需要用到的redux props state和redux props dispatch;
将this.state.ingredients全部改为this.props.ings
将this.state.totalprice 全部改为this.props.price
将purchasable直接传入BuildControl,不经过setstate;
import React, { Component } from 'react';
import Aux from '../../hoc/_Aux/_Aux';
import Burger from '../../components/Burger/Burger';
import BuildControls from '../../components/Burger/BuildControls/BuildControls';
import Modal from '../../components/UI/Modal/Modal';
import OrderSummary from '../../components/Burger/OrderSummary/OrderSummary';
import Spinner from '../../components/UI/Spinner/Spinner';
import withErrorHandler from '../../hoc/withErrorHandler/withErrorHandler';
import axios from '../../axios-orders';
import {connect} from 'react-redux';
import * as actionType from '../../store/actions';
class BurgerBuilder extends Component {
state = {
purchasing: false,
loading: false,
error: false
}
componentDidMount () { //用于从database抓取初始ingredient
console.log(this.props)
}
updatePurchaseState ( ingredients ) {
const sum = Object.keys( ingredients )
.map( igKey => {
return ingredients[igKey];
} )
.reduce( ( sum, el ) => {
return sum + el;
}, 0 );
return sum > 0
}
purchaseHandler = () => {
this.setState( { purchasing: true } );
}
purchaseCancelHandler = () => {
this.setState( { purchasing: false } );
}
purchaseContinueHandler = () => {
const queryParams= [];
for(let i in this.props.ings){
queryParams.push(encodeURIComponent(i)+'='+encodeURIComponent(this.props.ings[i])); //将code转为可用在url的形式
};
queryParams.push('price='+this.props.price);
const queryString = queryParams.join('&');
this.props.history.push({
pathname:'/checkout',
search: '?'+queryString
});
}
render () {
const disabledInfo = {
...this.props.ings
};
for ( let key in disabledInfo ) {
disabledInfo[key] = disabledInfo[key] <= 0
}
let orderSummary = null;
let burger = this.state.error ? <p>Ingredients can't be loaded!</p> : <Spinner />;
if ( this.props.ings ) {
burger = (
<Aux>
<Burger ingredients={this.props.ings} />
<BuildControls
ingredientAdded={this.props.onIngredientAdded}
ingredientRemoved={this.props.onIngredientRemoved}
disabled={disabledInfo}
purchasable={this.updatePurchaseState(this.props.ings)} //传入ings
ordered={this.purchaseHandler}
price={this.props.price} />
</Aux>
);
orderSummary = <OrderSummary
ingredients={this.props.ings}
price={this.props.price}
purchaseCancelled={this.purchaseCancelHandler}
purchaseContinued={this.purchaseContinueHandler} />;
}
if ( this.state.loading ) {
orderSummary = <Spinner />;
}
// {salad: true, meat: false, ...}
return (
<Aux>
<Modal show={this.state.purchasing} modalClosed={this.purchaseCancelHandler}>
{orderSummary}
</Modal>
{burger}
</Aux>
);
}
}
const mapStateToProps= state=>{
return{
ings:state.ingredients,
price:state.totalPrice
};
};
const mapDispatchToProps=dispatch=>{
return{
onIngredientAdded:(ingName)=>dispatch({type:actionType.ADD_INGREDIENTS,ingredientName:ingName}),
onIngredientRemoved:(ingName)=>dispatch({type:actionType.REMOVE_INGREDIENTS,ingredientName:ingName})
};
};
export default connect(mapStateToProps,mapDispatchToProps)(withErrorHandler( BurgerBuilder, axios ));
在checkout中用redux代替query的传递
BurgerBuilder.js中无需设置复杂的route
continue直接进入简单的checkout即可;
purchaseContinueHandler = () => {
this.props.history.push('/checkout');
}
checkout.js
route无需向下传入query数据,直接进入contact-data,传入component即可;
import React , {Component} from 'react';
import CheckoutSummary from '../../components/order/CheckoutSummary/CheckoutSummary';
import {Route} from 'react-router-dom';
import ContactData from '../ContactData/ContactData';
import {connect} from 'react-redux';
class Checkout extends Component{
checkoutCancelledHandler=()=>{
this.props.history.goBack();
}
checkoutContinuedHandler=()=>{
this.props.history.replace(this.props.match.url+'/contact-data');
}
render(){
return(
<div>
<CheckoutSummary
ingredients={this.props.ings}
checkoutCancelled={this.checkoutCancelledHandler}
checkoutContinued={this.checkoutContinuedHandler}/>
<Route
path={this.props.match.path + '/contact-data'}
component={ContactData}
/>
</div>
);
}
};
const mapStateToProps =state=>{
return{
ings: state.ingredients
}
};
export default connect(mapStateToProps)(Checkout);
在contactData中需要用到price和ingredients,无需从checkout中接收
由redux传入,调用即可;
省去蛮烦的query传递;
const mapStateToProps = state=>{
return{
ings:state.ingredients,
price:state.totalPrice
}
};
export default connect(mapStateToProps)(ContactData);