简体   繁体   中英

Set all radio buttons to false, then set one to true in Redux reducer

I can't seem to get my head around how to efficiently set all the radio buttons in a redux state to false then set the original action creator to true.

Right now I struggle by trying to copy the state object using Object.assign whilst also providing a way to change the objects which hold true for item.type === 'radio' to false .

Some code I thought might be close to the true way.

const state = {
  'some_id_1': {
    type: 'radio',
    id: 'some_id_1',
    checked: true
  }, 
  'some_id_2': {
    type: 'radio',
    id: 'some_id_2',
    checked: false
  }, 
  'some_id_3': {
    type: 'checkbox',
    id: 'some_id_3',
    checked: false
  }
};

const state = Object.assign({}, state, (item) => {
  if(item.type === 'radio') {
    console.log('reset='+item);
    item.checked = false;
  }
  return item;
});
return state;

But of course this doesn't work as it's not how Object.assign works.

Of course I could also loop over the object's keys, ie 'radio_box_1_id', ... and set anything with item.type === 'radio' to false, or even bring these changed values out to a separate state object and replace it using another argument of Object.assign . But these seem like extra processing time and not the perfect solution I'm looking for.

Thanks

Edit: My goal is to set the items of my state to a state of NOT checked, if they are a radio, but try not to change the others. I want to do this efficiently if it's possible. I can set the right radio afterwards to true.

Although you didn't specify the state shape nor your reducer code, this is a common operation.

If i understand correctly, you have an array of items (objects) with a type and id for each.
If the type is a radio then you will have a checked property.

If this is correct, you can use the Array.prototype.map() method and conditionally return a new object (using the object spread ) while you check the id inside your action payload.

Here is a small example:

 const state = [{ type: 'radio', id: 1, checked: true }, { type: 'radio', id: 2, checked: false }, { type: 'text', id: 88, value: 'hi there' }, { type: 'radio', id: 43, checked: false }]; const action = { id: 2 }; console.log('before the change', state); const nextState = state.map((item) => { if (item.type === 'radio') { return { ...item, checked: item.id === action.id } } return item; // not a radio, go on. }); console.log('after the change', nextState); 

Update
As a followup to your update, now that we know the shape of your state, when dealing with objects instead of arrays, you can iterate over the keys with Object.keys and use Array.prototype.reduce() to create a new object according to your conditions:

 const state = { 'some_id_1': { type: 'radio', id: 'some_id_1', checked: true }, 'some_id_2': { type: 'radio', id: 'some_id_2', checked: false }, 'some_id_3': { type: 'checkbox', id: 'some_id_3', checked: false } }; const action = { id: 'some_id_2' }; console.log('before the change', state); const nextState = Object.keys(state).reduce((result,currentKey) => { const currentItem = state[currentKey]; if (currentItem.type === 'radio') { result[currentKey] = { ...currentItem, checked: currentItem.id === action.id } } else{ result[currentKey] = currentItem // not a radio, go on. } return result; },{}); console.log('after the change', nextState); 

Edit
As a followup to Ulysse BN's comment:

I had to downvote: your modified answer doesn't fully clone the state. if after your code I run state['some_id_3'].foo = 'bar', nextState will be modified as well since they share the same object reference.

This is misleading, if you are not mutating an object then there is no need to re-create it. This is not a mutation.

This is a common practice in redux , you can learn more about it in Updating an Item in an Array

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM