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

[v1] new implementation without react context #35

Merged
merged 1 commit into from Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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