erikras / react-redux-universal-hot-example

A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform
MIT License
11.99k stars 2.5k forks source link

How to clear/remove state properties? #962

Closed realbugger closed 8 years ago

realbugger commented 8 years ago

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.

bhj commented 8 years ago

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.

realbugger commented 8 years ago

Got it. That makes sense. Thanks a lot.

sebkouba commented 8 years ago

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

matyasfodor commented 7 years ago

Another solution would be

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

Is there something wrong with:

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

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

ghost commented 6 years ago

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.

prufrock123 commented 6 years ago

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?

ghost commented 6 years ago

@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?

ghost commented 6 years ago

More notes on StackOverflow about ESLint defaults.

tyasink commented 4 years ago

this code cleans all state variables

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

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

fiznool commented 3 years ago

Since the introduction of destructuring and rest syntax to JavaScript, this can now be accomplished in another way:

const { data, ...rest } = state;
return {
  ...rest,
  loading: false,
  loaded: false
}