redux-react-hook
Advanced tools
Comparing version 3.1.0 to 3.2.0
# Changelog for redux-react-hook | ||
## v3.2.0 | ||
Feb 21, 2019 | ||
- Avoid double render if new mapState returns same mappedState (thanks @Turanchoks!) | ||
- Add create function for better typing (@thanks nmn!) | ||
## v3.1.0 | ||
@@ -4,0 +11,0 @@ |
/// <reference types="react" /> | ||
import { Action, Dispatch, Store } from 'redux'; | ||
export declare const StoreContext: import("react").Context<Store<any, import("redux").AnyAction> | null>; | ||
/** | ||
* Your passed in mapState function should be memoized with useCallback to avoid | ||
* resubscribing every render. If you don't use other props in mapState, pass | ||
* an empty array [] as the dependency list so the callback isn't recreated | ||
* every render. | ||
* | ||
* const todo = useMappedState(useCallback( | ||
* state => state.todos.get(id), | ||
* [id], | ||
* )); | ||
*/ | ||
export declare function useMappedState<TState, TResult>(mapState: (state: TState) => TResult): TResult; | ||
export declare function useDispatch<TAction extends Action>(): Dispatch<TAction>; | ||
import { create } from './create'; | ||
export declare const StoreContext: import("react").Context<any>, useDispatch: () => import("redux").Dispatch<any>, useMappedState: <TResult>(mapState: (state: any) => TResult) => TResult; | ||
export { create }; |
@@ -39,79 +39,94 @@ import { createContext, useContext, useState, useRef, useEffect } from 'react'; | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved | ||
var StoreContext = createContext(null); | ||
var CONTEXT_ERROR_MESSAGE = 'redux-react-hook requires your Redux store to ' + | ||
'be passed through context via the <StoreContext.Provider>'; | ||
/** | ||
* Your passed in mapState function should be memoized with useCallback to avoid | ||
* resubscribing every render. If you don't use other props in mapState, pass | ||
* an empty array [] as the dependency list so the callback isn't recreated | ||
* every render. | ||
* | ||
* const todo = useMappedState(useCallback( | ||
* state => state.todos.get(id), | ||
* [id], | ||
* )); | ||
* To use redux-react-hook with stronger type safety, or to use with multiple | ||
* stores in the same app, create() your own instance and re-export the returned | ||
* functions. | ||
*/ | ||
function useMappedState(mapState) { | ||
var store = useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
var mapStateFactory = function () { return mapState; }; | ||
var runMapState = function () { return mapState(store.getState()); }; | ||
var _a = useState(runMapState), derivedState = _a[0], setDerivedState = _a[1]; | ||
// If the store or mapState change, rerun mapState | ||
var _b = useState(store), prevStore = _b[0], setPrevStore = _b[1]; | ||
var _c = useState(mapStateFactory), prevMapState = _c[0], setPrevMapState = _c[1]; | ||
// We keep lastDerivedState in a ref and update it imperatively | ||
// after calling setDerivedState so it's always up-to-date. | ||
// We can't update it in useEffect because state might be updated | ||
// synchronously multiple times before render occurs. | ||
var lastDerivedState = useRef(derivedState); | ||
var wrappedSetDerivedState = function () { | ||
var newDerivedState = runMapState(); | ||
if (!shallowEqual(newDerivedState, lastDerivedState.current)) { | ||
setDerivedState(newDerivedState); | ||
lastDerivedState.current = newDerivedState; | ||
function create() { | ||
var StoreContext = createContext(null); | ||
/** | ||
* Your passed in mapState function should be memoized with useCallback to avoid | ||
* resubscribing every render. If you don't use other props in mapState, pass | ||
* an empty array [] as the dependency list so the callback isn't recreated | ||
* every render. | ||
* | ||
* const todo = useMappedState(useCallback( | ||
* state => state.todos.get(id), | ||
* [id], | ||
* )); | ||
*/ | ||
function useMappedState(mapState) { | ||
var store = useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
}; | ||
if (prevStore !== store || prevMapState !== mapState) { | ||
setPrevStore(store); | ||
setPrevMapState(mapStateFactory); | ||
wrappedSetDerivedState(); | ||
} | ||
useEffect(function () { | ||
var didUnsubscribe = false; | ||
// Run the mapState callback and if the result has changed, make the | ||
// component re-render with the new state. | ||
var checkForUpdates = function () { | ||
if (didUnsubscribe) { | ||
// Don't run stale listeners. | ||
// Redux doesn't guarantee unsubscriptions happen until next dispatch. | ||
return; | ||
var runMapState = function () { return mapState(store.getState()); }; | ||
var _a = useState(runMapState), derivedState = _a[0], setDerivedState = _a[1]; | ||
var lastStore = useRef(store); | ||
var lastMapState = useRef(mapState); | ||
// Keep lastDerivedState in a ref and update it imperatively | ||
// after calling setDerivedState so it's always up-to-date. | ||
// We can't update it in useEffect because state might be updated | ||
// synchronously multiple times before render occurs. | ||
var lastDerivedState = useRef(derivedState); | ||
var wrappedSetDerivedState = function () { | ||
var newDerivedState = runMapState(); | ||
if (!shallowEqual(newDerivedState, lastDerivedState.current)) { | ||
setDerivedState(newDerivedState); | ||
lastDerivedState.current = newDerivedState; | ||
} | ||
}; | ||
// If the store or mapState change, rerun mapState | ||
if (lastStore.current !== store || lastMapState.current !== mapState) { | ||
lastStore.current = store; | ||
lastMapState.current = mapState; | ||
wrappedSetDerivedState(); | ||
}; | ||
// Pull data from the store after first render in case the store has | ||
// changed since we began. | ||
checkForUpdates(); | ||
// Subscribe to the store to be notified of subsequent changes. | ||
var unsubscribe = store.subscribe(checkForUpdates); | ||
// The return value of useEffect will be called when unmounting, so | ||
// we use it to unsubscribe from the store. | ||
return function () { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [store, mapState]); | ||
return derivedState; | ||
} | ||
function useDispatch() { | ||
var store = useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
useEffect(function () { | ||
var didUnsubscribe = false; | ||
// Run the mapState callback and if the result has changed, make the | ||
// component re-render with the new state. | ||
var checkForUpdates = function () { | ||
if (didUnsubscribe) { | ||
// Don't run stale listeners. | ||
// Redux doesn't guarantee unsubscriptions happen until next dispatch. | ||
return; | ||
} | ||
wrappedSetDerivedState(); | ||
}; | ||
// Pull data from the store after first render in case the store has | ||
// changed since we began. | ||
checkForUpdates(); | ||
// Subscribe to the store to be notified of subsequent changes. | ||
var unsubscribe = store.subscribe(checkForUpdates); | ||
// The return value of useEffect will be called when unmounting, so | ||
// we use it to unsubscribe from the store. | ||
return function () { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [store, mapState]); | ||
return derivedState; | ||
} | ||
return store.dispatch; | ||
function useDispatch() { | ||
var store = useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
return store.dispatch; | ||
} | ||
return { | ||
StoreContext: StoreContext, | ||
useDispatch: useDispatch, | ||
useMappedState: useMappedState, | ||
}; | ||
} | ||
export { StoreContext, useMappedState, useDispatch }; | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved | ||
var _a; | ||
var StoreContext = (_a = create(), _a.StoreContext), useDispatch = _a.useDispatch, useMappedState = _a.useMappedState; | ||
export { StoreContext, useDispatch, useMappedState, create }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -43,81 +43,97 @@ 'use strict'; | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved | ||
var StoreContext = react.createContext(null); | ||
var CONTEXT_ERROR_MESSAGE = 'redux-react-hook requires your Redux store to ' + | ||
'be passed through context via the <StoreContext.Provider>'; | ||
/** | ||
* Your passed in mapState function should be memoized with useCallback to avoid | ||
* resubscribing every render. If you don't use other props in mapState, pass | ||
* an empty array [] as the dependency list so the callback isn't recreated | ||
* every render. | ||
* | ||
* const todo = useMappedState(useCallback( | ||
* state => state.todos.get(id), | ||
* [id], | ||
* )); | ||
* To use redux-react-hook with stronger type safety, or to use with multiple | ||
* stores in the same app, create() your own instance and re-export the returned | ||
* functions. | ||
*/ | ||
function useMappedState(mapState) { | ||
var store = react.useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
var mapStateFactory = function () { return mapState; }; | ||
var runMapState = function () { return mapState(store.getState()); }; | ||
var _a = react.useState(runMapState), derivedState = _a[0], setDerivedState = _a[1]; | ||
// If the store or mapState change, rerun mapState | ||
var _b = react.useState(store), prevStore = _b[0], setPrevStore = _b[1]; | ||
var _c = react.useState(mapStateFactory), prevMapState = _c[0], setPrevMapState = _c[1]; | ||
// We keep lastDerivedState in a ref and update it imperatively | ||
// after calling setDerivedState so it's always up-to-date. | ||
// We can't update it in useEffect because state might be updated | ||
// synchronously multiple times before render occurs. | ||
var lastDerivedState = react.useRef(derivedState); | ||
var wrappedSetDerivedState = function () { | ||
var newDerivedState = runMapState(); | ||
if (!shallowEqual(newDerivedState, lastDerivedState.current)) { | ||
setDerivedState(newDerivedState); | ||
lastDerivedState.current = newDerivedState; | ||
function create() { | ||
var StoreContext = react.createContext(null); | ||
/** | ||
* Your passed in mapState function should be memoized with useCallback to avoid | ||
* resubscribing every render. If you don't use other props in mapState, pass | ||
* an empty array [] as the dependency list so the callback isn't recreated | ||
* every render. | ||
* | ||
* const todo = useMappedState(useCallback( | ||
* state => state.todos.get(id), | ||
* [id], | ||
* )); | ||
*/ | ||
function useMappedState(mapState) { | ||
var store = react.useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
}; | ||
if (prevStore !== store || prevMapState !== mapState) { | ||
setPrevStore(store); | ||
setPrevMapState(mapStateFactory); | ||
wrappedSetDerivedState(); | ||
} | ||
react.useEffect(function () { | ||
var didUnsubscribe = false; | ||
// Run the mapState callback and if the result has changed, make the | ||
// component re-render with the new state. | ||
var checkForUpdates = function () { | ||
if (didUnsubscribe) { | ||
// Don't run stale listeners. | ||
// Redux doesn't guarantee unsubscriptions happen until next dispatch. | ||
return; | ||
var runMapState = function () { return mapState(store.getState()); }; | ||
var _a = react.useState(runMapState), derivedState = _a[0], setDerivedState = _a[1]; | ||
var lastStore = react.useRef(store); | ||
var lastMapState = react.useRef(mapState); | ||
// Keep lastDerivedState in a ref and update it imperatively | ||
// after calling setDerivedState so it's always up-to-date. | ||
// We can't update it in useEffect because state might be updated | ||
// synchronously multiple times before render occurs. | ||
var lastDerivedState = react.useRef(derivedState); | ||
var wrappedSetDerivedState = function () { | ||
var newDerivedState = runMapState(); | ||
if (!shallowEqual(newDerivedState, lastDerivedState.current)) { | ||
setDerivedState(newDerivedState); | ||
lastDerivedState.current = newDerivedState; | ||
} | ||
}; | ||
// If the store or mapState change, rerun mapState | ||
if (lastStore.current !== store || lastMapState.current !== mapState) { | ||
lastStore.current = store; | ||
lastMapState.current = mapState; | ||
wrappedSetDerivedState(); | ||
}; | ||
// Pull data from the store after first render in case the store has | ||
// changed since we began. | ||
checkForUpdates(); | ||
// Subscribe to the store to be notified of subsequent changes. | ||
var unsubscribe = store.subscribe(checkForUpdates); | ||
// The return value of useEffect will be called when unmounting, so | ||
// we use it to unsubscribe from the store. | ||
return function () { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [store, mapState]); | ||
return derivedState; | ||
} | ||
function useDispatch() { | ||
var store = react.useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
react.useEffect(function () { | ||
var didUnsubscribe = false; | ||
// Run the mapState callback and if the result has changed, make the | ||
// component re-render with the new state. | ||
var checkForUpdates = function () { | ||
if (didUnsubscribe) { | ||
// Don't run stale listeners. | ||
// Redux doesn't guarantee unsubscriptions happen until next dispatch. | ||
return; | ||
} | ||
wrappedSetDerivedState(); | ||
}; | ||
// Pull data from the store after first render in case the store has | ||
// changed since we began. | ||
checkForUpdates(); | ||
// Subscribe to the store to be notified of subsequent changes. | ||
var unsubscribe = store.subscribe(checkForUpdates); | ||
// The return value of useEffect will be called when unmounting, so | ||
// we use it to unsubscribe from the store. | ||
return function () { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [store, mapState]); | ||
return derivedState; | ||
} | ||
return store.dispatch; | ||
function useDispatch() { | ||
var store = react.useContext(StoreContext); | ||
if (!store) { | ||
throw new Error(CONTEXT_ERROR_MESSAGE); | ||
} | ||
return store.dispatch; | ||
} | ||
return { | ||
StoreContext: StoreContext, | ||
useDispatch: useDispatch, | ||
useMappedState: useMappedState, | ||
}; | ||
} | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved | ||
var _a; | ||
var StoreContext = (_a = create(), _a.StoreContext), useDispatch = _a.useDispatch, useMappedState = _a.useMappedState; | ||
exports.StoreContext = StoreContext; | ||
exports.useDispatch = useDispatch; | ||
exports.useMappedState = useMappedState; | ||
exports.useDispatch = useDispatch; | ||
exports.create = create; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "redux-react-hook", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "React hook for accessing a Redux store.", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -172,2 +172,30 @@ # redux-react-hook | ||
### `create()` | ||
Creates an instance of Redux React Hooks with a new `StoreContext`. The above functions are just exports of the default instance. You may want to create your own instance if: | ||
1. You want better type safety without annotating every callsite. Creating your own instance ensures that the types are the same for all consumers. See the example for more info. | ||
2. You have multiple Redux stores (this is not common) | ||
```tsx | ||
// MyStoreHooks.js | ||
import {create} from 'redux-react-hook'; | ||
export const {StoreContext, useDispatch, useMappedState} = create(); | ||
``` | ||
```tsx | ||
// MyStoreHooks.ts | ||
import {create} from 'redux-react-hook'; | ||
// Example in TypeScript where you have defined IState and Action | ||
export const {StoreContext, useDispatch, useMappedState} = create< | ||
IState, | ||
Action, | ||
Store<IState, Action> | ||
>(); | ||
``` | ||
## Example | ||
@@ -174,0 +202,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
39169
12
277
249