react-shared-state-hook

0.1.0 • Public • Published

react-shared-state-hook Build status

Simple React shared state hook based on useState

Installation

npm i react-shared-state-hook

Basic usage

import React from 'react';
import { createSharedStateHook } from 'react-shared-state-hook';
 
const [useSharedState, setSharedState] = createSharedStateHook({ a: 1, b: 2 });
// setSharedState({ a: 1, b: 3 }); // update state and trigger re-render
 
const ComponentA = () => {
  const state = useSharedState(); // re-render on any change
  return (
    <div>
      {state.a} + {state.b}
    </div>
  );
};
 
const ComponentB = () => {
  const b = useSharedState(o => o.b); // only re-render when b changes
  return <div>{b}</div>;
};

Example application setup

// index.ts
import React from 'react';
import ReactDOM from 'react-dom';
import { App } from './App';
 
ReactDOM.render(React.createElement(App), document.getElementById('root'));
// App.tsx
import React from 'react';
import { useActions, useAppState } from './state';
 
export const App = () => (
  <>
    <UsernameControl />
    <CountControl />
  </>
);
 
const UsernameControl = () => {
  const username = useAppState(o => o.username);
  const actions = useActions();
  return (
    <div>
      <p>Hello {username || '...'}</p>
      <input value={username ?? ''onChange={e => actions.setUsername(e.target.value)} />
    </div>
  );
};
 
const CountControl = () => {
  const count = useAppState(o => o.count);
  const actions = useActions();
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => actions.increaseCount()}>+1</button>
    </div>
  );
};
// state.ts
import { createSharedStateHook } from 'react-shared-state-hook';
import * as actions from './actions';
 
export interface AppState {
  username: string | null;
  count: number;
}
 
let appState: AppState = {
  username: null,
  count: 1,
};
 
const [useAppStateHook, setAppState] = createSharedStateHook(appState);
const [useActionsHook] = createSharedStateHook(actions);
 
export const useAppState = useAppStateHook;
export const useActions = useActionsHook;
 
export const getState = () => appState;
export const setState = (update: Partial<AppState>) => {
  const newState: AppState = { ...appState, ...update };
  appState = newState;
  setAppState(appState);
};
// actions.ts
import { setState, getState } from './state';
 
export function setUsername(username: string) {
  setState({ username });
}
 
export function increaseCount() {
  setState({ count: getState().count + 1 });
}

Transforming data structures

When the selector function returns a new object, the component will re-render on every state update. To prevent this, either split up into multiple hook calls, pass an isEqual function or memoize state selections.

Renders on each state update:

const Component = () => {
  const myState = useAppState(o => ({ a: o.count, b: o.username, t: '...' })); 
  return <div>..</div>
};

Using multiple hook calls (and create objects outside of selectors):

const Component = () => {
  const a = useAppState(o => o.count);
  const b = useAppState(o => o.username);
  const myState = { a, b, t: '...' };
  return <div>..</div>
};

Passing an isEqual function:

import { shallowEqual } from 'other-npm-module';
 
const Component = () => {
  const myState = useAppState(o => ({ a: o.count, b: o.username, t: '...' }), shallowEqual); 
  return <div>..</div>
};

Or memoize selections using something like reselect:

const myStateSelector = createSelector<AppState>(
  o => o.count,
  o => o.username,
  (a, b) => ({ a, b, t: '...' })
);
 
const Component = () => {
  const myState = useAppState(myStateSelector);
  return <div>..</div>
};

Mixing local state with shared state

const CountControl = () => {
  const [ownCount, setOwnCount] = useState(0);
  const countText = useAppState(o => `Count: ${o.count} (current ownCount: ${ownCount})`);
  const ownCountText = `Own count: ${ownCount}`;
  const actions = useActions();
  return (
    <div>
      <p>{countText}</p>
      <p>{ownCountText}</p>
      <button onClick={() => actions.increaseCount()}>+1 shared</button>
      <button onClick={() => setOwnCount(ownCount + 1)}>+1 own</button>
    </div>
  );
};

Package Sidebar

Install

npm i react-shared-state-hook

Weekly Downloads

2

Version

0.1.0

License

MIT

Unpacked Size

16.4 kB

Total Files

9

Last publish

Collaborators

  • marcelbeumer