npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@borvik/react-selector-context

v1.0.0

Published

What is `react-selector-context`?

Downloads

594

Readme

react-selector-context

What is react-selector-context?

Simply put, it provides for the ability to use a react context in a more redux and state like manner.

There is one big advantage to using some like react-redux. Re-render performance.

With react-redux, any changes to the global state only trigger rerenders to the components listening to the portion that changed - all while still being "one context".

With the standard context provided by react, any component that uses the context (the consumer or the useContext hook) re-renders any time anything on the context changed.

This attempts to bring the re-render performance of react-redux to a react context.

This component and examples were inspired by an article by Daniel Merrill.

Usage

The usage is very similar to the usage to a mix of the context api and state, which you can read in their documentation.

The difference, you cannot use a context created via the context api, specifically you can't use the useContext hook nor static contextType. The context created here also returns a useSelector hook and a withSelector method tied to this context. It also returns a useSetter, useGetter and a useState.

[!WARNING] While using this like a state provider is the preferred way - it does break the value attribute you can pass to the provider. As long as the provider doesn't re-render, all your state changes should be fine - but if you are using value and the provider re-renders, it will reset the data store the the contents of value.

import { createContext } from '@borvik/react-selector-context';

const { Provider, Consumer, useSelector, withSelector } = createContext({
  clicks: 0,
  time: 0,
  incrementClick: (_: number) => {},
});

createContext takes as it's only parameter the initial state of context - which behaves slightly differently than the built-in. With the built-in api, the initial state provided here is used when a Provider component isn't rendered. With this one, the Provider component is required, and the initial state is used if a value is not passed to the Provider.

With the exception of the value now being optional - the usage of the Provider is essentially the same.

const SomeComponent: React.FC = ({ children }) => {
  const [clicks, setClicks] = useState(0);
  const [time, setTime] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => setTime(v => v + 1), 1000);
    return () => clearInterval(interval);
  }, [setTime]);

  const incrementClick = useCallback((by: number) => {
    setClicks(v => v + by);
  }, [setClicks]);

  const value = useMemo(() => ({
    clicks,
    time,
    incrementClick,
  }), [clicks, time, incrementClick]);

  return <Provider value={value}>{children}</Provider>
}

createContext also returns a paired useSelector hook. This hook is similar to the same hook found in react-redux and takes a single callback function to return the parts of the context you are interested in.

const Clicker: React.FC = ({}) => {
  const { clicks, incrementClick } = useSelector(cb => ({clicks: cb.clicks, incrementClick: cb.incrementClick}));

  return (
    <div>
      <span>Clicks: {clicks}</span>
      <button onClick={() => incrementClick(1)}>Click Me</button>
    </div>
  );
}

Here is an example using the Consumer.

const Timer: React.FC = () => {
  return <div>
    <Consumer selector={cb => cb.time}>
      {(time) => (<span>Time: {time}</span>)}
    </Consumer>
  </div>;
}

And an example using withSelector as a higher-order-component.

class TimerBase extends React.Component<any> {
  render() {
    console.log('Render TIMER');
    const { selectorValue: time } = this.props;
    return <div><span>Time: {time}</span></div>;
  }
}
const Timer = withSelector(cb => cb.time)(TimerBase);

But, createContext here also returns some state-like functions useGetter, useSetter, and useState.

useGetter returns a fuction that will give you the full current state from the provider. This can be useful in event handlers where you don't really need your component to rerender as the state changes - but temporarily grabbing data to do validation is handy. Currently I don't have a proper example of this.

useSetter returns a function that allows you to alter the data inside the provider. You may specify a partial state, or a callback function that receives the current state and returns a partial state - just like React's built-in setState (for class components).

useState (not to be confused with React's version) takes selector callback function to get just the data you want, just like the useSelector - but, it returns a tuple, containing first the data you requested, but also the same setting function from useSetter.

const { Provider, useState: useClickState } = createContext({
  clicks: 0,
  time: 0,
});

const Clicker: React.FC = () => {
  const [clicks, setClickState] = useClickState(cb => cb.clicks);

  return (
    <div>
      <span>Clicks: {clicks}</span>
      <button onClick={() => setClickState(p => ({ clicks: p.clicks + 1 }))}>Click Me</button>
    </div>
  );
}