diff --git a/src/__tests__/useSelector.test.js b/src/__tests__/useSelector.test.js
index afe17fc..cce7dd0 100644
--- a/src/__tests__/useSelector.test.js
+++ b/src/__tests__/useSelector.test.js
@@ -21,7 +21,52 @@ describe('useSelector', () => {
store = createStore({})
})
- describe('core subscription behavior', () => {
+ describe('core select by string subscription behaviour ', () => {
+ let tester
+
+ beforeEach(() => {
+ store.setState({
+ foo: 'foo',
+ bar: 'bar'
+ })
+
+ const Comp = () => {
+ const { foo, bar } = useSelector('foo,bar')
+
+ return (
+
+ )
+ }
+
+ tester = ptl.render(
+
+
+
+ )
+ })
+
+ it('selects the state on intial render', () => {
+ expect(tester.getByTestId('foo')).toHaveTextContent('foo')
+ expect(tester.getByTestId('bar')).toHaveTextContent('bar')
+ })
+
+ it('selects the state and renders the component when the store updates', () => {
+ ptl.act(() => {
+ store.setState({
+ foo: 'fooB',
+ bar: 'barB'
+ })
+ })
+
+ expect(tester.getByTestId('foo')).toHaveTextContent('fooB')
+ expect(tester.getByTestId('bar')).toHaveTextContent('barB')
+ })
+ })
+
+ describe('core selector function subscription behavior', () => {
let tester
beforeEach(() => {
diff --git a/src/index.js b/src/index.js
index 9a95499..0afa2ac 100644
--- a/src/index.js
+++ b/src/index.js
@@ -9,12 +9,26 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffec
const refEquality = (a, b) => a === b
+// select('foo,bar') creates a function of the form: ({ foo, bar }) => ({ foo, bar })
+const select = (properties) => {
+ properties = properties.split(/\s*,\s*/)
+
+ return state => {
+ const selected = {}
+ for (let i = 0; i < properties.length; i++) {
+ selected[properties[i]] = state[properties[i]]
+ }
+ return selected
+ }
+}
+
export const StoreContext = createContext(null)
export const StoreProvider = StoreContext.Provider
export const useStore = () => useContext(StoreContext)
+// selector can be a string 'foo,bar' or a function (state => state.foo)
export const useSelector = (selector, equalityFn = refEquality) => {
const store = useStore()
const [, forceRerender] = useReducer(s => s + 1, 0)
@@ -22,12 +36,14 @@ export const useSelector = (selector, equalityFn = refEquality) => {
const selectorRef = useRef(null)
const selectedStateRef = useRef(null)
const onChangeErrorRef = useRef(null)
+ const isSelectorStr = (typeof selector === 'string')
let selectedState
try {
if (selectorRef.current !== selector || onChangeErrorRef.current) {
- selectedState = selector(store.getState())
+ const state = store.getState()
+ selectedState = isSelectorStr ? select(selector)(state) : selector(state)
} else {
selectedState = selectedStateRef.current
}
@@ -43,7 +59,7 @@ export const useSelector = (selector, equalityFn = refEquality) => {
}
useIsomorphicLayoutEffect(() => {
- selectorRef.current = selector
+ selectorRef.current = isSelectorStr ? select(selector) : selector
selectedStateRef.current = selectedState
onChangeErrorRef.current = null
})