pelotom / use-methods

A simpler way to useReducers
MIT License
705 stars 22 forks source link

Is there a way to use Set types as part of the state? #30

Open azinod opened 4 years ago

azinod commented 4 years ago

It doesn't seem to work out of the box, is there a way to enable/use them?

Example:

// CREATING STATE AND ACTIONS
import useMethods from 'use-methods';

const initialState = {
  idList: new Set()
};

const methods = state => ({
  addId: id =>{state.idList.add(id)},
  removeId: id => {state.idList.delete(id)}
});

const [state, actions] = useMethods(methods, initialState);

// USAGE
actions.addId(123); //does update the state but does not trigger a re-render
azinod commented 4 years ago

So, adding a bit more info to this... it actually does update the state, but does not trigger a re-render unless you completely replace the Set for another value.

As a workaround, I had to to add the following:

// CREATING STATE AND ACTIONS
import useMethods from 'use-methods';

const initialState = {
  idList: new Set(),
  __forceRender__: false // (1) this is part of the workaround,
};

const methods = state => ({
  addId: id => {
    state.idList.add(id);
    state.__forceRender__ = !state.__forceRender__; // (1) this is part of the workaround
},
  removeId: id => {
    state.idList.delete(id);
    state.__forceRender__ = !state.__forceRender__; // (1) this is part of the workaround
},
__firstRender: () => {state.__doneFirstRender__ = true;} // (2) this is part of the workaround
});

const [state, actions] = useMethods(methods, {
    ...initialState,
     __doneFirstRender__: false // (2) this is part of the workaround
  }
);

// (2) this is part of the workaround
React.useEffect(() => {
  if(!state.__doneFirstRender__){
    actions.__firstRender__();
  }
}, []);

// USAGE
actions.addId(123); //now it works

Explaining the workaround above:

  1. As you may gues, the update to __forceRender__ triggers a re-render, so my components now reflect my state properly.

  2. After I have done (1), a new bug was introduced: if the functions with the workaround were the first ones to update the state, they would run twice (and render component twice as well). So I had to add that __doneFirstRender__ thing to make sure the state was already "touched" so that the functions with workaround would not trigger the initial re-render twice.

Can you confirm if this is a bug or if I am just not doing it correctly @pelotom?

If its a bug I will try to investigate it and submit a PR if I manage to get it fixed.

ivmi commented 3 years ago

I am experiencing the same issue with Map type. I have also noticed that in the line: const [state, actions] = useMethods(methods, initialState);

the initialState gets mutated when using action. So you probably should not use the proposed workaround.

The weird thing is, if i copy the source of useMethods to my project and import it, everything works fine.