Simple React state management using context and hooks
import { createContainer } from '@namannehra/react-container';
import { useState } from 'react';
const useCounterContainer = initialCount => {
const [count, setCount] = useState(initialCount);
const increment = () => {
setCount(count => count + 1);
};
return { count, increment };
};
const [CounterProvider, useCounter] = createContainer(useCounterContainer);
const Counter = () => {
const { count, increment } = useCounter();
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
};
const App = () => (
<CounterProvider value={0}>
<Counter></Counter>
<Counter></Counter>
</CounterProvider>
);
Let's start with a simple component.
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count => count + 1);
};
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
};
If you want to share the logic then you can put it in a custom hook.
const useCounter = initialCount => {
const [count, setCount] = useState(initialCount);
const increment = () => {
setCount(count => count + 1);
};
return { count, increment };
};
const Counter = () => {
const { count, increment } = useCounter(0);
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
};
If you want to share the state then you can use context.
const useCounter = initialCount => {
const [count, setCount] = useState(initialCount);
const increment = () => {
setCount(count => count + 1);
};
return { count, increment };
};
const CounterContext = createContext();
const CounterProvider = props => {
const counter = useCounter(props.value);
return <CounterContext.Provider value={counter}>{props.children}</CounterContext.Provider>;
};
const Counter = () => {
const { count, increment } = useContext(CounterContext);
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
};
const App = () => (
<CounterProvider value={0}>
<Counter></Counter>
<Counter></Counter>
</CounterProvider>
);
You can do the same with createContainer()
. A container is just a pair of provider and hook.
const useCounterContainer = initialCount => {
const [count, setCount] = useState(initialCount);
const increment = () => {
setCount(count => count + 1);
};
return { count, increment };
};
const [CounterProvider, useCounter] = createContainer(useCounterContainer);
const Counter = () => {
const { count, increment } = useCounter();
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
};
const App = () => (
<CounterProvider value={0}>
<Counter></Counter>
<Counter></Counter>
</CounterProvider>
);
useCreateContainer => [Provider, useContainer, NoProviderError]
useCreateContainer
: (value: Value) => Result
Provider
: Component<{value: Value}>
useContainer
: () => Result
NoProviderError
: Subclass<Error>
You should set the displayName
of provider.
Learn more
const [CounterProvider, useCounter] = createContainer(...);
CounterProvider.displayName = 'CounterProvider';
You can use standard React optimizations like useCallback()
and useMemo()
.
const useCounterContainer = initialCount => {
const [count, setCount] = useState(initialCount);
const increment = useCallback(() => {
setCount(count => count + 1);
}, [setCount]);
return { count, increment };
};
const [CounterProvider, useCounter] = createContainer(useCounterContainer);
https://github.com/jamiebuilds/unstated-next
The idea for this project came from unstated-next.