ฉันจะเพิ่มองค์ประกอบลงในอาร์เรย์ในตัวลดรีแอคทีลักซ์รีแอกทีฟได้อย่างไร


140

ฉันจะเพิ่มองค์ประกอบใน array arr[]ของ redux state ใน reducer ได้อย่างไร ฉันกำลังทำสิ่งนี้ -

import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {
    arr:[]
}

export default function userState(state = initialUserState, action)
{
    console.log(arr);
    switch (action.type)
    {
        case ADD_ITEM: 
            return { 
                      ...state,
                      arr: state.arr.push([action.newItem])
                   }

        default:
            return state
    }
}

คำตอบ:


363

สองตัวเลือกที่แตกต่างกันเพื่อเพิ่มรายการในอาร์เรย์โดยไม่มีการกลายพันธุ์

case ADD_ITEM :
    return { 
        ...state,
        arr: [...state.arr, action.newItem]
    }

หรือ

case ADD_ITEM :
    return { 
        ...state,
        arr: state.arr.concat(action.newItem)
    }

1
สิ่งใดที่ควรพิจารณาว่าเหมาะสมกว่า
sapht

19
@sapht หากคุณกำลังเขียนโค้ดใน ES6 สิ่งที่ชอบคืออันแรกซึ่งเป็น IMO ที่อ่านง่ายและสง่างาม
Yadhu Kiran

5
อีกอย่างคืออันแรกนั้นบริสุทธิ์และอันที่สองไม่ใช่ จาก Redux docs: "มันสำคัญมากที่ตัวลดยังคงบริสุทธิ์อยู่สิ่งที่คุณไม่ควรทำในตัวลด: 1. ทำให้เกิดการโต้แย้งของมัน 2. ทำผลข้างเคียงเช่นการเรียก API และการเปลี่ยนเส้นทาง 3. เรียกฟังก์ชันที่ไม่บริสุทธิ์ เช่น Date.now () หรือ Math.random () "
หุ่นยนต์ที่มีเสน่ห์

สวัสดี @YadhuKiran คุณสามารถอธิบายให้ฉันทำไมเราเพิ่มมูลค่าใหม่ในดัชนีที่สองของอาร์เรย์ฉันไม่สามารถเข้าใจได้ดีมาก? arr: [...state.arr, why here?]
Oliver D

@OliverD เมื่อมีการใช้ไวยากรณ์การแพร่กระจายดังกล่าวข้างต้นจะไม่แทรกองค์ประกอบที่ดัชนีที่สอง แต่ที่ดัชนีสุดท้าย ตรงกันข้ามกับสิ่งนี้[action.newItem, ...state.arr]จะแทรกองค์ประกอบที่ตำแหน่งแรก
Yadhu Kiran

22

pushไม่ส่งคืนอาร์เรย์ แต่ความยาวของมัน ( docs ) ดังนั้นสิ่งที่คุณกำลังทำคือการแทนที่อาร์เรย์ด้วยความยาวของมันสูญเสียการอ้างอิงเดียวกับที่คุณมี ลองสิ่งนี้:

import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {

    arr:[]
}

export default function userState(state = initialUserState, action){
     console.log(arr);
     switch (action.type){
        case ADD_ITEM :
          return { 
             ...state,
             arr:[...state.arr, action.newItem]
        }

        default:return state
     }
}

1
ทุกคนสามารถตอบคำถามนี้ด้วยObject.assignสำหรับการเปลี่ยนแปลงของอาร์เรย์ภายในรัฐได้ไหม
Vennesa

2
ทำไมคุณต้องObject.assign? มันใช้สำหรับวัตถุและมันก็เป็นสิ่งเดียวกัน arr:[...state.arr, action.newItem]คุณสามารถใช้ที่ไหนโดยมีobj: Object.assign({}, state.obj, action.newItemเงื่อนไขobjและnewItemเป็นวัตถุ หากคุณต้องการทำเช่นนั้นกับรัฐทั้งหมดคุณสามารถทำได้Object.assign({}, state, {arr: [..state.arr, action.newItem]})
martinarroyo

1
@martinarroyo ขอบคุณฉันทำ: var obj = { isLoading: true, data: ['a', 'b', 'c', 'd'] } var newObj = Object.assign({}, obj, { data: [...obj.data, 'e'] });และมันทำให้ฉันนี้: { isLoading: true, data: [ 'a', 'b', 'c', 'd', 'e' ] }สำหรับ newObj ซึ่งดีพอสำหรับสิ่งที่ฉันต้องการ แต่ฉันต้องการใช้ Object.assign โดยไม่มีตัวดำเนินการ spread เพื่อสร้างผลลัพธ์เดียวกัน เป็นไปได้ไหม
Vennesa

1
@Vennesa ฉันเดาว่าคุณสามารถแทนที่ด้วย[].concat(obj.data, ['e'])ถ้าคุณไม่ต้องการใช้คุณสมบัติ ES6 Object.assign นั้นมีไว้สำหรับวัตถุและแม้ว่ามันจะไม่ให้ข้อผิดพลาดใด ๆ แก่คุณในการใช้งานกับอาเรย์ ถ้าคุณลองObject.assign({}, [1, 2, 3], [4])คุณจะได้รับ[4, 2, 3]ผลลัพธ์
martinarroyo

13

หากคุณต้องการแทรกลงในตำแหน่งเฉพาะในอาเรย์คุณสามารถทำได้:

case ADD_ITEM :
    return { 
        ...state,
        arr: [
            ...state.arr.slice(0, action.pos),
            action.newItem,
            ...state.arr.slice(action.pos),
        ],
    }

ฉันสะดุดที่นี่ ... แม้ว่าคำตอบนี้จะไม่ตรงกับคำถามข้างต้น อย่างไรก็ตามมันเป็นสิ่งที่ฉันกำลังมองหา ฉันกำลังมองหาวิธีแทรกวัตถุในดัชนีเฉพาะในอาร์เรย์ ดังนั้นฉันลงคะแนนคำตอบแล้ว มันมีประโยชน์มากและช่วยฉันในบางครั้ง ขอบคุณ!
omostan

0

ฉันมีตัวอย่าง

import * as types from '../../helpers/ActionTypes';

var initialState = {
  changedValues: {}
};
const quickEdit = (state = initialState, action) => {

  switch (action.type) {

    case types.PRODUCT_QUICKEDIT:
      {
        const item = action.item;
        const changedValues = {
          ...state.changedValues,
          [item.id]: item,
        };

        return {
          ...state,
          loading: true,
          changedValues: changedValues,
        };
      }
    default:
      {
        return state;
      }
  }
};

export default quickEdit;

1
เพิ่มคำอธิบายบางอย่าง
SPatel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.