javascript - 状态数组上的多个不可变更改

标签 javascript reactjs ecmascript-6 redux immutability

我有以下currentState。当我添加收件人时,新收件人应附加到recipient.allIds和recipientProduct,默认数量= 1。我一直坚持附加到recipientProduct部分。这应该以不可变的方式完成,因为它是一个 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'
    }],
}

最佳答案

我认为它是一个应该处理所描述的逻辑的reducer,而不是一个 Action 创建者(?)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>

关于javascript - 状态数组上的多个不可变更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59676475/

相关文章:

reactjs - BlueprintJS 树添加 key 属性

reactjs - 如何定义Redux中reducer的执行顺序?

javascript - 在 TSX 文件 : Property 'createRef' does not exist on type 'typeof React'

Javascript 正则表达式 : how to match ONLY the given characters?

javascript - 隐藏 x 轴上的刻度线会剪裁图表 (Chart.JS)

javascript - .insertBefore() 不是函数 javascript

javascript - 为什么箭头函数不能在 Electron 引用的脚本中工作?

javascript - 从字符串创建 react 组件

javascript - 如何将 GraphQL 中的对象元素推送到 javascript 对象中的嵌套数组中?

javascript - javascript可以在客户端捕获图像下载时间吗?