Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Shallow equality option for useStoreState() #354

Merged
merged 2 commits into from
Jan 17, 2020

Conversation

joelmoss
Copy link
Contributor

@joelmoss joelmoss commented Nov 8, 2019

Currently. useStoreState() performs a strict equality check (oldState === newState) on its state, which is great for most cases. But sometimes you need to work with more complex state and return something that will always fail a strict check.

This PR adds support for a shallow equality check as follows:

const store = createStore({
  count: 1,
  firstName: null,
  lastName: null
});

// In your component
const { count, firstName } = useStoreState(
  state => ({
    count: state.count,
    firstName: state.firstName,
  }),
  { shallowEquality: true }, /* this is new, an is false by default */
);

In the above case, if either the count or firstName state vars change, the equality check with be true, and the component will re-render. And if any other state is changed; for example, the lastName, the equality check will be true, and the component will not re-render.

The shallowEquality option is false by default, thus maintaining existing functionality.

See #275

@codecov
Copy link

codecov bot commented Nov 8, 2019

Codecov Report

Merging #354 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #354   +/-   ##
=======================================
  Coverage   97.76%   97.76%           
=======================================
  Files          20       20           
  Lines         581      581           
  Branches      113      113           
=======================================
  Hits          568      568           
  Misses         11       11           
  Partials        2        2

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8c534dc...01ead48. Read the comment docs.

@joelmoss
Copy link
Contributor Author

@ctrlplusb anything I can do to push this along?

@ctrlplusb
Copy link
Owner

Hi @joelmoss - shall endeavour to review this week. I have had a very busy past few weeks.

@joelmoss
Copy link
Contributor Author

joelmoss commented Nov 23, 2019 via email

@ctrlplusb
Copy link
Owner

@joelmoss I've had a look. Thanks so much for this. Will be an awesome addition.

I'd like to request that we change the API somewhat. Instead of the configuration object could we instead accept an equality function as the second argument to useStoreState. This would very much be in line with the Redux useSelector hook then.

We could include a default shallow equality fn that user's could leverage.

This provides a lot more flexibility going forward IMO.

@joelmoss
Copy link
Contributor Author

ok, yeah I like that. Leave it with me.

@joelmoss
Copy link
Contributor Author

By the way, I noticed that the shallowequal package is included, so we can use that as the officialy provided equality function.

However, I'm not seeing why that package is included and where it used.

@joelmoss
Copy link
Contributor Author

Actually, no matter. The shallowequal package accepts a customizer which we don't and won't ever use.

@joelmoss
Copy link
Contributor Author

done!

@ctrlplusb
Copy link
Owner

Amazing thanks!

@crissdev
Copy link
Contributor

@joelmoss Thanks for this feature. If possible please squash your commits into one and update the docs/example found in this commit 1d29a67, since it no longer matches the final implementation. This might be very useful to @ctrlplusb if he decides to use that in the documentation.

Currently. useStoreState() performs a strict equality check
(`oldState === newState`) on its state, which is great for most cases.
But sometimes you need to work with more complex state and return
something that will always fail a strict check.

This PR adds support for providing a custom equality function as
follows:

```javascript
const store = createStore({
  count: 1,
  firstName: null,
  lastName: null
});

// In your component
const { count, firstName } = useStoreState(
  state => ({
    count: state.count,
    firstName: state.firstName,
  }),
  (prevState, nextState) => {
    // perform some equality comparison here
    return shallowEqual(prevState, nextState)
  }
);
```

In the above case, if either the `count` or `firstName` state vars
change, the equality check with be true, and the component will
re-render. And if any other state is changed; for example, the
`lastName`, the equality check will be true, and the component will not
re-render.

An exported `shallowEqual()` function is provided to allow you to run
shallow equality checks: `useStoreState(map, shallowEqual)`.

See ctrlplusb#275
@joelmoss
Copy link
Contributor Author

Done!

@crissdev
Copy link
Contributor

@joelmoss Cool. I think index.d.ts should also be updated to include the changes to useStoreState and the new shallowEqual function. Do you want to give that a try?

@joelmoss
Copy link
Contributor Author

joelmoss commented Dec 1, 2019

Not familiar with TS, but will give it a go

@ctrlplusb
Copy link
Owner

@joelmoss - if you aren't comfortable with doing the TS don't stress. Let me know and I will pick that up for ya.

@joelmoss
Copy link
Contributor Author

joelmoss commented Dec 9, 2019 via email

@joelmoss
Copy link
Contributor Author

joelmoss commented Jan 2, 2020

@ctrlplusb Just had a thought about this PR in the context of computed properties; do they also have a strict equality check? If so, we should probably allow this new option with computed properties too.

@ctrlplusb ctrlplusb merged commit 92f4e01 into ctrlplusb:master Jan 17, 2020
ctrlplusb added a commit that referenced this pull request Jan 17, 2020
…354)

Currently. useStoreState() performs a strict equality check
(`oldState === newState`) on its state, which is great for most cases.
But sometimes you need to work with more complex state and return
something that will always fail a strict check.

This PR adds support for providing a custom equality function as
follows:

```javascript
const store = createStore({
  count: 1,
  firstName: null,
  lastName: null
});

// In your component
const { count, firstName } = useStoreState(
  state => ({
    count: state.count,
    firstName: state.firstName,
  }),
  (prevState, nextState) => {
    // perform some equality comparison here
    return shallowEqual(prevState, nextState)
  }
);
```

In the above case, if either the `count` or `firstName` state vars
change, the equality check with be true, and the component will
re-render. And if any other state is changed; for example, the
`lastName`, the equality check will be true, and the component will not
re-render.

An exported `shallowEqual()` function is provided to allow you to run
shallow equality checks: `useStoreState(map, shallowEqual)`.

See #275

Co-authored-by: Sean Matheson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants