Skip to content

Commit

Permalink
Merge pull request #35 from dai-shi/implementation-without-context
Browse files Browse the repository at this point in the history
[v1] new implementation without react context
  • Loading branch information
dai-shi committed Jan 23, 2020
2 parents 3525543 + 37040bb commit 455802a
Show file tree
Hide file tree
Showing 40 changed files with 313 additions and 377 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -2,7 +2,7 @@

## [Unreleased]
### Changed
- Reduce bundle size a little
- New API without context

## [0.17.0] - 2020-01-09
### Changed
Expand Down
29 changes: 10 additions & 19 deletions README.md
Expand Up @@ -8,10 +8,8 @@ Simple global state for React with Hooks API

## Introduction

If you ever try to implement a global state with Context and Hooks,
you probably find it straightforward.
This library provide more or less the same functionality
with some following bonuses.
This is a library to provide a global state with React Hooks.
It has following characteristics.

- Optimization for shallow state getter and setter.
- The library cares the state object only one-level deep.
Expand All @@ -20,9 +18,8 @@ with some following bonuses.
- Redux middleware support to some extent
- Some of libraries in Redux ecosystem can be used.
- Redux DevTools Extension could be used in a simple scenario.

Due to the fact that this library utilizes `unstable_observedBits`
for optimization, this library is still in alpha.
- Concurrent Mode support (Experimental)
- Undocumented `useGlobalStateProvider` supports CM without React Context.

## Install

Expand All @@ -39,7 +36,7 @@ import React from 'react';
import { createGlobalState } from 'react-hooks-global-state';

const initialState = { count: 0 };
const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
const { useGlobalState } = createGlobalState(initialState);

const Counter = () => {
const [count, setCount] = useGlobalState('count');
Expand All @@ -55,10 +52,10 @@ const Counter = () => {
};

const App = () => (
<GlobalStateProvider>
<>
<Counter />
<Counter />
</GlobalStateProvider>
</>
);
```

Expand All @@ -76,7 +73,7 @@ const reducer = (state, action) => {
}
};
const initialState = { count: 0 };
const { GlobalStateProvider, dispatch, useGlobalState } = createStore(reducer, initialState);
const { dispatch, useGlobalState } = createStore(reducer, initialState);

const Counter = () => {
const [value] = useGlobalState('count');
Expand All @@ -90,10 +87,10 @@ const Counter = () => {
};

const App = () => (
<GlobalStateProvider>
<>
<Counter />
<Counter />
</GlobalStateProvider>
</>
);
```

Expand Down Expand Up @@ -123,12 +120,6 @@ You can also try them in codesandbox.io:
[12](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/12_effect)
[13](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/13_persistence)

## Limitations

- Due to the implementation relying on `observedBits` in the Context API,
the performance may drop down if a state holds more than 30 items.
Reference: [#1](https://github.com/dai-shi/react-hooks-global-state/issues/1)

## Blogs

- [TypeScript-aware React hooks for global state](https://blog.axlight.com/posts/typescript-aware-react-hooks-for-global-state/)
Expand Down
14 changes: 7 additions & 7 deletions __tests__/01_basic_spec.js
@@ -1,4 +1,4 @@
import React from 'react';
import React, { StrictMode } from 'react';
import { render, fireEvent, cleanup } from '@testing-library/react';

import { createGlobalState, createStore } from '../src/index';
Expand All @@ -12,7 +12,7 @@ describe('basic spec', () => {

it('should be possible to not specify initial state', () => {
const reducer = () => ({ count: 0 });
const { GlobalStateProvider, useGlobalState } = createStore(reducer);
const { useGlobalState } = createStore(reducer);
const Counter = () => {
const [value, update] = useGlobalState('count');
return (
Expand All @@ -23,9 +23,9 @@ describe('basic spec', () => {
);
};
const App = () => (
<GlobalStateProvider>
<StrictMode>
<Counter />
</GlobalStateProvider>
</StrictMode>
);
const { getByText } = render(<App />);
expect(getByText('0')).toBeDefined();
Expand All @@ -37,7 +37,7 @@ describe('basic spec', () => {
const initialState = {
count1: 0,
};
const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [value, update] = useGlobalState('count1');
return (
Expand All @@ -48,10 +48,10 @@ describe('basic spec', () => {
);
};
const App = () => (
<GlobalStateProvider>
<StrictMode>
<Counter />
<Counter />
</GlobalStateProvider>
</StrictMode>
);
const { getAllByText, container } = render(<App />);
expect(container).toMatchSnapshot();
Expand Down
8 changes: 4 additions & 4 deletions __tests__/02_useeffect_spec.js
@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { StrictMode, useEffect } from 'react';
import { render, cleanup } from '@testing-library/react';

import { createGlobalState } from '../src/index';
Expand All @@ -10,7 +10,7 @@ describe('useeffect spec', () => {
const initialState = {
count1: 0,
};
const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [value, update] = useGlobalState('count1');
useEffect(() => {
Expand All @@ -23,9 +23,9 @@ describe('useeffect spec', () => {
);
};
const App = () => (
<GlobalStateProvider>
<StrictMode>
<Counter />
</GlobalStateProvider>
</StrictMode>
);
const { container } = render(<App />);
expect(container).toMatchSnapshot();
Expand Down
18 changes: 7 additions & 11 deletions __tests__/03_startup_spec.js
@@ -1,4 +1,4 @@
import React from 'react';
import React, { StrictMode } from 'react';
import { render, cleanup } from '@testing-library/react';

import { createGlobalState, createStore } from '../src/index';
Expand All @@ -11,7 +11,7 @@ describe('startup spec', () => {
count1: 0,
count2: 0,
};
const { GlobalStateProvider, setGlobalState, useGlobalState } = createGlobalState(initialState);
const { setGlobalState, useGlobalState } = createGlobalState(initialState);
const Counter = ({ name }) => {
setGlobalState(name, 9);
const [value] = useGlobalState(name);
Expand All @@ -23,10 +23,10 @@ describe('startup spec', () => {
);
};
const App = () => (
<GlobalStateProvider>
<StrictMode>
<Counter name="count1" />
<Counter name="count2" />
</GlobalStateProvider>
</StrictMode>
);
const { getByTestId } = render(<App />);
expect(getByTestId('count1').innerHTML).toBe('9');
Expand All @@ -47,11 +47,7 @@ describe('startup spec', () => {
}
return state;
};
const {
GlobalStateProvider,
dispatch,
useGlobalState,
} = createStore(reducer, initialState);
const { dispatch, useGlobalState } = createStore(reducer, initialState);
const Counter = ({ name }) => {
dispatch({ type: 'setCounter', name, value: 9 });
const [value] = useGlobalState(name);
Expand All @@ -63,10 +59,10 @@ describe('startup spec', () => {
);
};
const App = () => (
<GlobalStateProvider>
<StrictMode>
<Counter name="count1" />
<Counter name="count2" />
</GlobalStateProvider>
</StrictMode>
);
const { getByTestId } = render(<App />);
expect(getByTestId('count1').innerHTML).toBe('9');
Expand Down
8 changes: 5 additions & 3 deletions dist/index.d.ts
@@ -1,10 +1,12 @@
import { ComponentType, SetStateAction, Reducer } from 'react';
import { SetStateAction, Reducer } from 'react';

type SetGlobalState<S> = <N extends keyof S>(
name: N,
setStateAction: SetStateAction<S[N]>,
) => void;

type UseGlobalStateProvider = () => void;

type UseGlobalState<S> = <N extends keyof S>(name: N) => [
S[N],
(setStateAction: SetStateAction<S[N]>) => void,
Expand All @@ -13,7 +15,7 @@ type UseGlobalState<S> = <N extends keyof S>(name: N) => [
export type Dispatch<A> = (action: A) => A;

export type Store<S, A> = {
GlobalStateProvider: ComponentType;
useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState<S>;
getState: () => S;
dispatch: Dispatch<A>;
Expand All @@ -26,7 +28,7 @@ export type Enhancer<S, A> = (creator: StoreCreator<S, A>) => StoreCreator<S, A>
type AnyEnhancer = unknown;

export type CreateGlobalState = <S>(initialState: S) => {
GlobalStateProvider: ComponentType;
useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState<S>;
setGlobalState: SetGlobalState<S>;
getGlobalState: <N extends keyof S>(name: N) => S[N];
Expand Down

0 comments on commit 455802a

Please sign in to comment.