Maboo
Maboo

Reputation: 425

Clearing an array state in Redux

How do I clear an array state in Redux? I have an initial state of an empty array, and things are being added. I want to have an action that just clear it, I tried the following method but it gives me "Unexpected token" error about the "action.payload" I give to the CLEAR_THINGS action:

export default (state=[], action) => {
switch (action.type) {
    case "RECEIVE_THING":
        return [
            ...state,
            action.payload
        ];
    case "CLEAR_THINGS":
        return {
            ...state,
            action.payload // payload here is []...
        };
    default:
        return state;
}}

It also throw the error if I just use [] instead of through action.payload.

Upvotes: 2

Views: 11712

Answers (4)

DDS
DDS

Reputation: 4375

export default (state=[], action) => {
switch (action.type) {
    case "RECEIVE_THING":
        return [
            ...state,
            action.payload
        ];
    case "CLEAR_THINGS":
        return [];
    default:
        return state;
}}

The RECEIVE_THING action uses object spread notation to return a state that is an array ([]) which contains the prior state ([...state]) and adds to that a new item ([...state, action.payload]). The key/property name used for this new item is simply the next index of the array. It is, after all, an array.

In your code for CLEAR_THINGS you are creating an object ({}) that contains the old state (say it was ['item1']) and so it looks like { '0': 'item1' }. Next you proceed to use object shorthand notation to add more state, but this requires you use a single identifier (a single word) but you're using a dotted notion (qualified identifier) to access a property. You're kind of instructing a property named action.payload be created but this is illegal and this is where your error comes from. The reason it works in the case of the array is because only a value is needed in this case, since the key is derived from the index of the array.

What you want to do is always return the same kind of object, in your case, an array. By starting with return {, you're already going the wrong way.

Upvotes: 6

Rich Costello
Rich Costello

Reputation: 95

I wound up finding the answer here on another stackoverflow thread.

The issue was because the function 'map' can only be used for arrays, not for objects. So in my image component I had to change

this.props.filtered.map((pic)

to

this.props.filtered.filtered.map((pic)

Upvotes: 0

Ben Sidelinger
Ben Sidelinger

Reputation: 1359

You should just return and empty array in your "CLEAR_THINGS" handler:

export default (state=[], action) => {
switch (action.type) {
    case "RECEIVE_THING":
        return [
            ...state,
            action.payload
        ];
    case "CLEAR_THINGS":
        return [];
    default:
        return state;
}}

Since you just want to clear everything there's not need to reference the existing state, you just want to set the new state to an empty array.

Another thing worth mentioning is that I'd probably nest my array in an object. If your reducer gains more complexity in the future it'll be hard to add functionality this way as you have it and this approach would allow your app to gain further complexity if needed. You can always add reducers of course, but I like making my reducers more flexible this way. This would look like:

export default (state = { myArray: [] }, action) => {
switch (action.type) {
    case "RECEIVE_THING":
        return {
            ...state,
            myArray: state.myArray.concat([action.payload]),
        };
    case "CLEAR_THINGS":
        return {
            ...state,
            myArray: [],
        };
    default:
        return state;
}}

Upvotes: 4

user5224313
user5224313

Reputation:

The ES6 shorthand for the operation

{thing}

transpiles to

{"thing": thing}

This causes a syntax error in your case because the key contains a period and it's unclear what the key should be. Maybe you intend for something like this?

return {
    action: {
        payload: action.payload
    }
}

But this doesn't solve the problem at hand: if you want to clear the array with this action, you should not expand the existing state into the next state. Instead you should just return something in the same shape as your existing state, but semantically has the meaning of empty (in this case, just an empty array). I think what you want is

case "RECEIVE_THING":
    return [
        ...state,
        action.payload
    ];
case "CLEAR_THINGS":
    return [];

Upvotes: 2

Related Questions