6

My store looks like this,

{
  name: "john",
  foo: {},
    arr: [
      {
        id:101,
        desc:'comment'
      },
      { 
        id:101,
        desc:'comment2'
      }
    ]
}

My textarea looks like this

<textarea
  id={arr.id} //"101"
  name={`tesc:`}
  value={this.props.store.desc}
  onChange={this.props.onChng}
/>

My action is

export const onChng = (desc) => ({
  type: Constants.SET_DESC,
  payload: {
    desc
  }
});

My reducer

case Constants.SET_DESC:
  return update(state, {
    store: {
      streams: {
        desc: { $set: action.payload.desc }
      } 
    }
});

It works only if arry is an object, I had to make changes to the stream to an array and I am confused how I can update to an array, also how does get the right value from the store.

6
  • 1
    How do you want to update the array? Modify an element in the array or add a new element, remove one, etc? Commented Aug 29, 2017 at 2:41
  • I want to add a new element? next to { id:101, here } Commented Aug 29, 2017 at 3:36
  • 1
    How do you determine the id? Commented Aug 29, 2017 at 3:38
  • I have udpated the textarea to have the same id as inside the stream array Commented Aug 29, 2017 at 3:43
  • 1
    So you want to add a new object to the streams array every time you type in the textarea, with the textarea's id and value as the description? Commented Aug 29, 2017 at 3:45

3 Answers 3

2

The following example taken from the redux documentation might help you in the use case how to update items in an array. For more on this you can read on here http://redux.js.org/docs/recipes/StructuringReducers.html

state structure is something like this

{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}

and reducer code is like below

function updateObject(oldObject, newValues) {
    // Encapsulate the idea of passing a new object as the first parameter
    // to Object.assign to ensure we correctly copy data instead of mutating
    return Object.assign({}, oldObject, newValues);
}

function updateItemInArray(array, itemId, updateItemCallback) {
    const updatedItems = array.map(item => {
        if(item.id !== itemId) {
            // Since we only want to update one item, preserve all others as they are now
            return item;
        }

        // Use the provided callback to create an updated item
        const updatedItem = updateItemCallback(item);
        return updatedItem;
    });

    return updatedItems;
}

function appReducer(state = initialState, action) {
    switch(action.type) {
        case 'EDIT_TODO' : {
            const newTodos = updateItemInArray(state.todos, action.id, todo => {
                return updateObject(todo, {text : action.text});
            });

            return updateObject(state, {todos : newTodos});
        } 
        default : return state;
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I was hoping to do it in the structure i have asked. Meaning how do u access an array in a store
state.todos is array
unfortunately i dont understand.. but thanks for trying
1

If you have to update an element in a array within your store you have to copy the array and clone the matching element to apply your changes.

So in the first step your action should contain either the already cloned (and changed) object or the id of the object and the properties to change.

Here is a rough example:

export class MyActions {
    static readonly UPDATE_ITEM = 'My.Action.UPDATE_ITEM';

    static updateItem(id: string, changedValues: any) {
        return { type: MyActions.UPDATE_ITEM, payload: { id, changedValues } };
    }
}

export const myReducer: Reducer<IAppState> = (state: IAppState = initialState, action: AnyAction): IAppState => {
    switch (action.type) {
        case MyActions.UPDATE_ITEM:
            return { ...state, items: merge(state.items, action.payload) };

        default:
            return state;
    }
}

const merge = (array, change) => {
    // check if an item with the id already exists
    const index = array.findIndex(item => item.id === change.id);
    // copy the source array
    array = [...array];

    if(index >= 0) {
        // clone and change the existing item
        const existingItem = array[index];
        array[index] = { ...existingItem, ...change.changedValues };
    } else {
        // add a new item to the array
        array.push = { id: change.id, ...change.changedValues };
    }

    return array;
}

2 Comments

what would the array look like in your example?
The array contains your objects. E.g. { id: string, desc: string }. If your object contains also an array of further objects you have to nest the above logic one level more and your changedValues object would also contain an id property. If this is your case and you don't know how to accomplish this, give me a hint and I'll update my answer.
0

To update an array, I would use immutability helper and do something like this - to your reducer

 let store = {"state" : {
"data": [{
    "subset": [{
        "id": 1
    }, {
        "id": 2
    }]
}, {
    "subset": [{
        "id": 10
    }, {
        "id": 11
    }, {
        "id": 12
    }]
}]
}}

case Constants.SET_DESC:
  return update(store, {
  "state" : {
  "data": {
      [action.indexToUpdate]: {
        "subset": {
             $set: action.payload.desc
        }
      }
  }
 }
  })
  });

1 Comment

This is how I want to implement it.. I have downloaded immutable-helper into my project but it not working - not finding indexToUpdate

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.