Search code examples
reactjsredux-toolkit

Array index not update/re-render with Redux State


I have parent.tsx that I can add Child item into a List and in child.tsx I can delete the item by clicking a button. The New item will be stored in state.childList.

The trouble is, after deleting a item from childList, I can spot the childList is updated in the state (via Redux devTools), However after that, when I'm trying to modify the left items, an old-index will be passed into the Child componenet then eveything goes wrong.

for example, say childList=[A,B,C]. I can delete B, then when I try to modify C, the log shows the passed in sequeceNumber is still 2 rather 1.

Here's parent.tsx

const { addChild, removeChild }: MyModalDispatch = selectDispatch(useDispatch());

const onRemoveChild = (sequenceNumber) => {
    removeChild(sequenceNumber;)
}

return( //render
    <SomeComponentes />
    <SomeComponentes />
    <SomeComponentes />
    {
        childList?.length > 0 && <div>
        {
        childList?.map((party, index) => {
        return (<ChildComponent key={party.id}, sequenceNumber={index}, onRemoveChild={onRemoveChild} />);
        })
        } </div>
    }
    <AddRemove>
        <IconLink label="remove this Child", onClick={addChild}
        </IconLink>
    </AddRemove>
    <SomeComponentes />
)

and here is my child.tsx where I can delete the Child:

const {sequenceNumber, onRemoveChild} = props;

const removeChildHandler = () => {
    onRemoveChild(sequenceNumber);
}

const modify = () => {
    modify(sequenceNumber);
}

return( //render
    <SomeComponentes />
    <SomeComponentes />
    <AddRemove>
        <IconLink label="remove this Child", onClick={removeChildHandler}
        </IconLink>
    </AddRemove>
)
and here is the reducer

and the reduce:

    reducer: {
        addChild: (state: MyState) => {
        // just push the new item into overall childList
        },
        removeChild: (state: MyState, sequenceNumber: number) => {
            const ChildList = state.childList;
            childList.splice(sequenceNumber, 1);
            
            return {
                ...state,
                childList
            }
        },
        modify: (state: MyState, sequenceNumber: number) => {
            //update a item from childList and push back to it.
            return {
                ...state,
                childList
            }
        }
    }
}

if dont delete any item, all other functions (add, modify, etc..) are working fine. Seems the parent.tsx/child.tsx failed to fetch the latest index, any proper method?

btw the project is just handovered to me, trying to fix this defect first, thanks

tried using

removeChild: (state: MyState, sequenceNumber: number) => {
            const newList = state.childList;
            newList.splice(sequenceNumber, 1);
            
            return {
                ...state,
                childList: newList 
            }
        }

and

removeChild: (state: MyState, sequenceNumber: number) => {
        const newList = [...state.childList];
        newList.splice(sequenceNumber, 1);
        
        return {
            ...state,
            childList: newList 
        }
    }

didnt work


Solution

  • Reducers don't get the payload, but the full action as second argument. You need to access the payload on that action.

    removeChild: (state: MyState, action: PayloadAction<number>) => {
                const ChildList = state.childList;
                childList.splice(action.payload, 1);
                
                return {
                    ...state,
                    childList
                }
            },
    

    Also, in RTK Query you can just modify state, no need to return a new one:

    removeChild: (state: MyState, action: PayloadAction<number>) => {
                state.childList.splice(action.payload, 1);
            },