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

react-hooks-simple-global-state

v1.1.3

Published

Simple global state for React with Hooks, which just depends on React's useEffect and useState.

Downloads

16

Readme

react-hooks-simple-global-state

Simple global state for React with Hooks, which just depends on React's useEffect and useState.

The idea here is simply to create a kind of useState that shares the information between all the different components that use the same stateName. For this, only the state and lifecycle control of React components with Hooks, associated with the Observer pattern, is used to synchronize the update of all independent states.

NOTE: If you have any difficulty, problem or even suggestion, please let me know here or here.

Install

npm install react-hooks-simple-global-state

or

yarn add react-hooks-simple-global-state

Interface

const useGlobalState = <T>(
  stateName: string,
  initValue?: T,
  listening?: boolean = true
) => [currentValue: T, setValue: FuncSetValue<T>];

Note that the structure is very similar to React's useState, but here we need to inform the stateName so we can distinguish which global state we want to use.

One important thing that can be noticed about initValue, is that it can have different values in each use of useGlobalState, but only one of them will actually be used, and that will be the one executed first during the rendering of React, that is, it follows the order of the component tree. But you don't have to worry about that, as there are ways to make it even easier, with the following examples.

The listening parameter can be set to false when you don't want to receive state updates. This can be useful when you just want to access the information, for example when you just need to access the FuncSetValue function, this prevents the current component from being updated unnecessarily.

const useAsyncGlobalState = <T>(
  stateName: string,
  funcLoadAsyncData?: () => Promise<T>
) => AsyncData<T> {
  loading: boolean;
  data?: T;
  error?: any;
  refetch: () => void;
};

Here, instead of an initial value, we pass an async function to generate the data. Note that this parameter is optional as we may want to use state only. And note that unlike initValue, here you don't need to have funcLoadAsyncData right on the first call, but it follows the same logic of using only the first place you call with this parameter. That way, if nobody passes this parameter, the state will be loading forever.

The biggest differentiator here with respect to useGlobalState is the return format, because here we are targeting more the asynchronous execution pattern.

Examples of use

You can use it in the simplest and most direct way:

import React from 'react';
import { useGlobalState } from 'react-hooks-simple-global-state';

const TabNavigation = () => {
  const [activeTab, setActiveTab] = useGlobalState('activeTab', 3);

  return (
    <>
      <button onClick={() => setActiveTab(activeTab - 1)}>Previous tab</button>
      {activeTab}
      <button onClick={() => setActiveTab((currentActiveTab) => currentActiveTab + 1)}>Next tab</button>
    </>
  );
};

export default TabNavigation;

To avoid having to repeat over and over or use constants for stateName or to not have difficulties with initValue, you can centralize this information in a single function:

// ...
const useActiveTab = () => useGlobalState('activeTab', 3);

const TabNavigation = () => {
  const [activeTab, setActiveTab] = useActiveTab();
  // ...
};

Another alternative to not having to worry about initValue is to use useEffect, as this guarantees the expected value in the global state:

import React, { useEffect } from 'react';
import useGlobalState from 'react-hooks-simple-global-state';

const TabNavigation = ({ initTab }) => {
  const [activeTab, setActiveTab] = useGlobalState('activeTab');

  useEffect(() => initTab && setActiveTab(initTab), []);

  if (activeTab == null) return 'Loading...';
  // ...
};

You may also need to work with asynchronous information, for example requests to an API:

// ------ In a file:
import React, { useEffect } from 'react';
import { useAsyncGlobalState } from 'react-hooks-simple-global-state';

const useUser = () => useAsyncGlobalState('user', () => (
  fetch('https://.../users/1')
    .then((response) => response.json())
));

// ------ In any other file:
const MyComponent1 = () => {
  const {
    data: user, loading, error, refetch
  } = useUser();

  if (loading) return 'Loading...';
  if (error) return 'Error :(';

  return (
    <>
      {`Name: ${user.name} `}
      <button onClick={refetch}>reload</button>
    </>
  );
};

// ------ In any other file:
const MyComponent2 = () => {
  const {
    data: user, loading, error, refetch
  } = useAsyncGlobalState('user');
  // ...
};

If you want to use actions(dispatchers), you can do for example like this:

// ...
const useDispatch = () => {
  const [count, setCount] = useGlobalState('count', 0, false);
  const actions = {
    COUNT_DECREMENT: (value = 1) => setCount(count - value),
    COUNT_INCREMENT: (value = 1) => setCount(count + value)
  };

  return (actionName, ...args) => actions[actionName]?.(...args);
};

const MyComponent = () => {
  const dispatch = useDispatch();
  const [count] = useGlobalState('count');

  return (
    <>
      {`count: ${count} `}
      <button onClick={() => dispatch('COUNT_DECREMENT', 2)}>-2</button>
      <button onClick={() => dispatch('COUNT_INCREMENT')}>+1</button>
    </>
  );
};

You can create an observer(subscribe) component as follows:

// ...
const CountObserver = () => {
  const [count] = useGlobalState('count');

  console.log(`Current count value: ${count}`);

  return null;
};

// And you can add it anywhere on the tree.
const App = () => (
  <>
    // ...
    <CountObserver />
    // ...
  </>
);

Practical examples