2

I would like to know, how can I move an object in array with Redux.

In my reducer I have this :

case SEQUENCES.MOVE_REPLY_ON_BLOCK :

indexBucket   = action.indexBucket; // => 0
indexBlock    = action.indexBlock; // => 0
indexReply    = action.indexReply; // => 1
replySelected = action.payload.reply; // => my reply object
newIndex      = action.payload.newIndex; // => 2


return {
    ...state,
    buckets: state.buckets.map((bucket, i) => i === indexBucket ? {
        ...bucket,
        blocks: bucket.blocks.map((block, i) => i === indexBlock ? {
            ...block,
            messages: block.messages.map((message, i) => i === 0 ? {
                ...message,
                replies: [
                    ...state.buckets[indexBucket].blocks[indexBlock].messages[0].replies.splice(indexReply, 1),
                    ...state.buckets[indexBucket].blocks[indexBlock].messages[0].replies.splice(newIndex, 0, replySelected)
                ]
            } : message)
        } : block)
    } : bucket)
};

My tree looks like that:

buckets[
    blocks[
        messages[
            replies [
                {my_object},
                {my_object},
                {my_object},
                ...
            ]
        ]
    ]
]

I would like move the reply object in replies array, but with my code, I have no error but all replies are remove...

5
  • This code looks overly complicated. And it's unclear exactly what it's supposed to do. What does "move object in array" mean here? Do you want to add a new object, or move some item that's already in the array to a different index?
    – Håken Lid
    Commented May 14, 2019 at 17:15
  • Thx @HåkenLid for your answer ! I would like to move some item already in the array. Do you have an idea how can I simplify this code ? Commented May 14, 2019 at 17:16
  • I'm guessing from indexReply to newIndex? What is replySelected then?
    – Håken Lid
    Commented May 14, 2019 at 17:22
  • Yes ! replySelected is my reply object {id:xxx, value:..} (in fact is state.buckets[indexBucket].blocks[indexBlock].messages[0].replies[indexReply]) Commented May 14, 2019 at 17:25
  • 1
    I'm not sure about particular issue but don't use splice since it modifies source array; use slice instead
    – skyboyer
    Commented May 14, 2019 at 17:49

1 Answer 1

3

There are several ways to deal with deeply nested data structures in Redux. There's a good article in the redux docs about Normalizing State Shape which could help avoid this problem altogether.

If flattening the state is not an option, I would recommend using a utility library to modify deeply nested objects. My preference is ramda.js, but lodash etc. also contain this kind of functionality.

With ramda, you can write reducers using "lenses" to change nested state without mutating the original state.

Using ramda, your return expression could be written like this:

// import * as R from 'ramda'

return R.over(
  R.lensPath([
    'buckets', action.indexBucket, 
    'blocks', action.indexBlock, 
    'messages', 0, 
    'replies',
  ]), 
  R.move(action.indexReply, action.payload.newIndex),
  state,
)

I'm not sure if this exactly solves your problem, because your question does not include a minimal, complete and verifiable example, but I think it's pretty close to what you want.

If you don't like ramda's functional programming style, you might want to check out immer for a completely different approach to immutable state.

It is possible to rewrite your code without using an utility library, but it's very difficult to avoid bugs, and your code will be much harder to read.

1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.