我有以下currentState
。当我添加收件人时,新的收件人应该附加到默认数量为1的accepter.allIds和receiveerProduct上。我被困在附加到recipientProduct
部分上。这应该在immutable way
中完成,因为它是Redux状态。
let currentState = {
product: {
allIds: ['1', '5'],
},
recipient: {
allIds: ['1'],
},
recipientProduct: [{
recipientId: '1',
productId: '1',
qty: '3'
}, {
recipientId: '1',
productId: '5',
qty: '3'
}],
};
当我添加新的收件人时:
addRecipient = (recipientId) => {
// when recipientId = 2
// note quantity is always default to 1
-> append productIds to product.allIds if not exists
-> loop through all product from product.allIds
loop through all recipient from recipient.allIds
if (recipientId === recipientId && productId === productId) {
remain
} else {
// append with default qty 1
}
}
这将是newState
:
newstate = {
product: {
allIds: ['1', '5'],
},
recipient: {
allIds: ['1', '2'],
},
recipientProduct: [{
recipientId: '1',
productId: '1',
qty: '3'
}, {
recipientId: '1',
productId: '5',
qty: '3'
},{
recipientId: '2',
productId: '1',
qty: '1'
}, {
recipientId: '2',
productId: '5',
qty: '1'
}],
}
答案 0 :(得分:2)
我认为这是应该处理所描述逻辑的化简器,而不是动作创建者(?)addRecipient
。
因此,据我所知,在常见的Redux工作流程中,您需要修改全局状态属性recipient
(应推入新的收件人)和recipientProduct
(与每个产品对应的项目,默认数量为派发APPEND_RECIPIENT
动作或类似动作时应添加1。
我对此的解决方案如下:
appReducer = (state=initialState, action) => {
switch(action.type){
case 'APPEND_RECIPIENT' : {
let {payload: recipientId} = action,
{recipient:{allIds:recipientIds}, recipientProduct, product:{allIds:productIds}} = state
if(recipientIds.includes(recipientId)) return state
recipientIds = [...recipientIds, recipientId]
recipientProduct = [...recipientProduct,...productIds.map(productId => ({productId, recipientId, qty: '1'}))]
return {...state, recipient:{allIds:recipientIds}, recipientProduct}
}
default: return state
}
}
您可以在下面找到该概念的实时演示:
//dependencies
const { useState } = React,
{ render } = ReactDOM,
{ createStore } = Redux,
{ connect, Provider } = ReactRedux
//initial state, reducer and store
const initialState = {product:{allIds:['1','5']},recipient:{allIds:['1']},recipientProduct:[{recipientId:'1',productId:'1',qty:'3'},{recipientId:'1',productId:'5',qty:'3'}]},
appReducer = (state=initialState, action) => {
switch(action.type){
case 'APPEND_RECIPIENT' : {
let {payload: recipientId} = action,
{recipient:{allIds:recipientIds}, recipientProduct, product:{allIds:productIds}} = state
if(recipientIds.includes(recipientId)) return state
recipientIds = [...recipientIds, recipientId]
recipientProduct = [...recipientProduct,...productIds.map(productId => ({productId, recipientId, qty: '1'}))]
return {...state, recipient:{allIds:recipientIds}, recipientProduct}
}
default: return state
}
},
store = createStore(appReducer)
//append recipient form ui component
const AppendRecipient = ({onAppendRecipient, onInput}) => {
const [inputValue, setInput] = useState()
return (
<form onSubmit={e => (e.preventDefault(), onAppendRecipient(inputValue))}>
<input type="number" onKeyUp={e => setInput(e.target.value)} />
<input type="submit" name="Append Recipient" />
</form>
)
}
//connect onAppendRecipient handler to dispatching 'APPEND_RECIPIENT' action
const mapDispatchToProps = dispatch => ({
onAppendRecipient: recipientId => dispatch({type:'APPEND_RECIPIENT', payload:recipientId})
}),
AppendRecipientContainer = connect(null, mapDispatchToProps)(AppendRecipient)
//mirroring recipientProducts
const RecipientProducts = ({products, productsQty}) => (
<div>
{
products.map(({recipientId,productId,qty},key) => <div {...{key}}>recipient:{recipientId}, product:{productId}, qty: {qty}</div>)
}
</div>
)
//connect output element to global recipientProducts
const mapStateToProps = ({recipientProduct}) => ({products:recipientProduct, productsQty:recipientProduct.length}),
RecipientProductsContainer = connect(mapStateToProps)(RecipientProducts)
//render the entire app
render (
<Provider store={store}>
<AppendRecipientContainer />
<RecipientProductsContainer />
</Provider>,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.3/react-redux.min.js"></script><div id="root"></div>
答案 1 :(得分:1)
您可以尝试这种逻辑吗?
const redux = require("redux");
const createStore = redux.createStore;
const ADD_RECIPIENT = "ADD_RECIPIENT";
const initialState = {
product: {
allIds: ["1", "5"]
},
recipient: {
allIds: ["1"]
},
recipientProduct: [
{
recipientId: "1",
productId: "1",
qty: "3"
},
{
recipientId: "1",
productId: "5",
qty: "3"
}
]
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_RECIPIENT:
const recipientId = action.recipientId;
const recipientExists = state.recipient.allIds.includes(recipientId);
if (!recipientExists) {
let recipientProducts = [...state.recipientProduct];
state.product.allIds.forEach(productId => {
let productIdExists =
state.recipientProduct.findIndex(r => r.productId === productId) >-1;
let recipientIdExists =
state.recipientProduct.findIndex( r => r.recipientId === recipientId) > -1;
if (!productIdExists || !recipientIdExists) {
recipientProducts.push({recipientId,productId,qty: "1"});
}
});
return {
...state,
recipient: {
allIds: [...state.recipient.allIds, recipientId]
},
recipientProduct: recipientProducts
};
}
return state;
default:
return state;
}
};
const store = createStore(reducer);
store.subscribe(() => {
console.log("[NEW STATE]", store.getState());
});
store.dispatch({
type: ADD_RECIPIENT,
recipientId: "2"
});
答案 2 :(得分:0)
您可以复制当前状态。修改对象,然后再次将该对象分配给状态。
addRecipient = (recipientId) => {
let copy = {...currentState};
copy.recipient.allIds.push(recipientId);
copy.product.allIds.map((product)=>{
let obj = {
recipientId: recipientId,
productId: product,
qty: '1'
}
copy.recipientProduct.push(obj);
});
//Now `copy` is your new state.Old object will be as it is.
//You can do anything with new object.
}
如果您正在使用redux,则可以调用action或setState并可以更改状态。 让我知道这是否对您有帮助。