Skip to content

Commit 9c7fc93

Browse files
committed
add useRedux hook
1 parent c525cb9 commit 9c7fc93

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed

src/alternate-renderers.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import connect from './connect/connect'
55

66
import { useActions } from './hooks/useActions'
77
import { useDispatch } from './hooks/useDispatch'
8+
import { useRedux } from './hooks/useRedux'
89
import { useSelector } from './hooks/useSelector'
910
import { useStore } from './hooks/useStore'
1011

@@ -21,6 +22,7 @@ export {
2122
batch,
2223
useActions,
2324
useDispatch,
25+
useRedux,
2426
useSelector,
2527
useStore
2628
}

src/hooks/useRedux.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useSelector } from './useSelector'
2+
import { useActions } from './useActions'
3+
4+
/**
5+
* A hook to access the redux store's state and to bind action creators to
6+
* the store's dispatch function. In essence, this hook is a combination of
7+
* `useSelector` and `useActions`.
8+
*
9+
* @param {Function} selector the selector function
10+
* @param {Function|Function[]|Object.<string, Function>} actions the action creators to bind
11+
*
12+
* @returns {[any, any]} a tuple of the selected state and the bound action creators
13+
*
14+
* Usage:
15+
*
16+
```jsx
17+
import React from 'react'
18+
import { useRedux } from 'react-redux'
19+
20+
export const CounterComponent = () => {
21+
const [counter, { inc1, inc }] = useRedux(state => state.counter, {
22+
inc1: () => ({ type: 'inc1' }),
23+
inc: amount => ({ type: 'inc', amount }),
24+
})
25+
26+
return (
27+
<>
28+
<div>
29+
{counter}
30+
</div>
31+
<button onClick={inc1}>Increment by 1</button>
32+
<button onClick={() => inc(5)}>Increment by 5</button>
33+
</>
34+
)
35+
}
36+
```
37+
*/
38+
export function useRedux(selector, actions) {
39+
return [useSelector(selector), useActions(actions)]
40+
}

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import connect from './connect/connect'
55

66
import { useActions } from './hooks/useActions'
77
import { useDispatch } from './hooks/useDispatch'
8+
import { useRedux } from './hooks/useRedux'
89
import { useSelector } from './hooks/useSelector'
910
import { useStore } from './hooks/useStore'
1011

@@ -21,6 +22,7 @@ export {
2122
batch,
2223
useActions,
2324
useDispatch,
25+
useRedux,
2426
useSelector,
2527
useStore
2628
}

test/hooks/useRedux.spec.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*eslint-disable react/prop-types*/
2+
3+
import React from 'react'
4+
import { createStore } from 'redux'
5+
import * as rtl from 'react-testing-library'
6+
import { Provider as ProviderMock, useRedux } from '../../src/index.js'
7+
8+
describe('React', () => {
9+
describe('hooks', () => {
10+
describe(useRedux.name, () => {
11+
let store
12+
let renderedItems = []
13+
14+
beforeEach(() => {
15+
store = createStore(({ count } = { count: -1 }) => ({
16+
count: count + 1
17+
}))
18+
renderedItems = []
19+
})
20+
21+
afterEach(() => rtl.cleanup())
22+
23+
it('selects the state and binds action creators', () => {
24+
const Comp = () => {
25+
const [count, { inc }] = useRedux(s => s.count, {
26+
inc: () => ({ type: '' })
27+
})
28+
renderedItems.push(count)
29+
return (
30+
<>
31+
<div>{count}</div>
32+
<button id="bInc" onClick={inc} />
33+
</>
34+
)
35+
}
36+
37+
const { container } = rtl.render(
38+
<ProviderMock store={store}>
39+
<Comp />
40+
</ProviderMock>
41+
)
42+
43+
const bInc = container.querySelector('#bInc')
44+
45+
rtl.fireEvent.click(bInc)
46+
47+
expect(renderedItems).toEqual([0, 1])
48+
})
49+
})
50+
})
51+
})

0 commit comments

Comments
 (0)