React-redux-universal-hot-example: How to clear/remove state properties?

Created on 26 Feb 2016  路  12Comments  路  Source: erikras/react-redux-universal-hot-example

Still learning React JS and Redux, and found this boilerplate to be extremely helpful. Good job Erik!

I'm wondering how to clear/remove a state property, say, state.data. Note that I don't want to just set state.data to null. I want to remove state.data property all together. The following code works for me.

.......
case CLEAR:
      delete state.data;
      return {
        ...state,
        loading: false,
        loaded: false
      };
.......

However, my understanding is that state in Redux should not be mutated. Although it's working, doesn't it violate the immutable rule of Redux? Actually, I don't see any code in the example making copies of state object before changing it, like most other Redux implementation does (see below).

......
  var newState = Object.assign({}, state);
  newState.data= action.data;
  return newState;
......

So how does the example code get away from the whole Object.assign thing? I must be missing something. Thanks.

Most helpful comment

My google search pointed me here and the answer above seemed vague. How about the following as implementation to removing keys...

It filters the key that should be deleted then builds a new object from the remaining keys and the initial object. The idea is stolen from Tyler McGinnes awesome reactjs program.

function removeByKey (myObj, deleteKey) {
  return Object.keys(myObj)
    .filter(key => key !== deleteKey)
    .reduce((result, current) => {
      result[current] = myObj[current];
      return result;
  }, {});
}

JSBin

All 12 comments

Although it's working, doesn't it violate the immutable rule of Redux?

Yes, the delete statement is mutating the previous state. You'll probably find this breaks time travel/undo/redo, which are core benefits of Redux to be ignored at your own peril!

I don't see any code in the example making copies of state object before changing it

That's what ...state is doing (copying the properties of the previous state to the new object literal that gets returned). It's an ES7 object spread initializer and I believe it does get transpiled down to Object.assign after Babel has its way with it.

Of course, whether deleting the data property altogether is actually a good idea or not is very debatable. I'd highly recommend rethinking this and keeping your state shapes consistent.

Got it. That makes sense. Thanks a lot.

My google search pointed me here and the answer above seemed vague. How about the following as implementation to removing keys...

It filters the key that should be deleted then builds a new object from the remaining keys and the initial object. The idea is stolen from Tyler McGinnes awesome reactjs program.

function removeByKey (myObj, deleteKey) {
  return Object.keys(myObj)
    .filter(key => key !== deleteKey)
    .reduce((result, current) => {
      result[current] = myObj[current];
      return result;
  }, {});
}

JSBin

Another solution would be

function removeKey(myObj, deleteKey) {
  return Object.assign(
    {},
    ...Object.entries(myObj)
       .filter(([k]) => k!== deleteKey)
       .map(([k, v]) => ({[k]: v})));
}

Is there something wrong with:

function removeKey(obj, deleteKey) {
  let clone = Object.assign({}, obj);
  delete clone[deleteKey];
  return clone;
}

@Halt001 If you change myObj parameter to obj so that function doesn't break, it's perfectly fine :)

You can use destructuring to remove the properties.

Here is a function that I use in my validation reducers to return a valid field state after making sure that the validation passed. It removes the invalid and error fields from the given fieldState object.

function validFieldState(fieldState) {
  if (fieldState.invalid) {
    const {
      invalid: _invalid,    // <-- The `_invalid` and `_error` variables are never used.
      error: _error,
      ...nextFieldState,  // <-- This variable gets every prop except for `invalid` and `error`.
    } = fieldState;
    return nextFieldState;
  }
  return fieldState;
}

This is a common pattern used in React, to remove certain props before copying them to a child component.

The only headache with your approach @waynebloss, is that a lot of linters do not allow unused variables. You can always disable a rule temporarily, but that kind of inconsistency is not ideal. Especially in a production deployment.

Are there any other approaches besides the ones mentioned here?

@prufrock123 I should have mentioned that the variables should be prefixed with an underscore as shown in my example, because the linter that is built into create-react-app will automatically ignore any unused variable that starts with an underscore.

This seems to be a common feature of other linters and I see it mentioned a few different places:

Couldn't find the official docs for tslint, but it should work.

Which linter are you using?

this code cleans all state variables

let cleanState = {};
Object.keys(this.state).forEach(x => cleanState[x] = null);
this.setState(cleanState);

I don't think that there's anything wrong with that method.

Was this page helpful?
0 / 5 - 0 ratings