Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commited6d414

Browse files
committed
Extend store object to return mapStoreToProps and connected
1 parentc4258e7 commited6d414

File tree

8 files changed

+95
-59
lines changed

8 files changed

+95
-59
lines changed

‎README.md‎

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,18 @@ type StoreState = { layout: LayoutState }
3939
const switchTheme=createAction('switchTheme')
4040

4141
// Build reducer
42-
const layoutReducer=newReducerBuilder<LayoutState>()
43-
.handle(switchTheme, (state,action)=> {
42+
const layoutReducer=newReducerBuilder<LayoutState>().handle(
43+
switchTheme,
44+
(state,action)=> {
4445
const isDark=!state.layout.isDark
4546
return {...state,isDark }
4647
},
4748
)
4849

4950
// Build store
50-
exportconst [store, mapStoreToProps]=newStoreBuilder<StoreState>()
51+
exportconst { mapStoreToProps, connected,...store }=newStoreBuilder<
52+
StoreState
53+
>()
5154
.withReducerBuildersMap({ layout:layoutReducer })
5255
.withDevTools()// enable chrome devtools
5356
.build()
@@ -56,14 +59,7 @@ export const [store, mapStoreToProps] = new StoreBuilder<StoreState>()
5659
```tsx
5760
importReactfrom'react'
5861
import {mapDispatchToProps }from'redux-ts'
59-
import {mapStoreToProps,store }from'./store'
60-
61-
// Connect store
62-
const Root:React.FC=props=> (
63-
<Providerstore={store}>
64-
<Main />
65-
</Provider>
66-
)
62+
import {connected,mapStoreToProps,store }from'./store'
6763

6864
// Map store to component props
6965
const storeProps=mapStoreToProps(store=> ({
@@ -74,11 +70,21 @@ const storeProps = mapStoreToProps(store => ({
7470
const dispatchProps=mapDispatchToProps({switchTheme })
7571

7672
// Connect component
77-
const Main=connect(storeProps,dispatchProps)(({theme,switchTheme })=> (
73+
const ConnectedMain=connected(
74+
storeProps,
75+
dispatchProps,
76+
)(({theme,switchTheme })=> (
7877
<div>
7978
<span>Current theme:{theme}</span>
8079
<buttononClick={switchTheme}>Switch theme</button>
8180
</div>
81+
))
82+
83+
// Connect store
84+
const Root:React.FC=props=> (
85+
<Providerstore={store}>
86+
<ConnectedMain />
87+
</Provider>
8288
)
8389

8490
ReactDOM.render(<Root />,document.getElementById('app'))
@@ -97,7 +103,7 @@ import { connectRouter, routerMiddleware } from 'connected-react-router'
97103

98104
exportconst history=createBrowserHistory()
99105
const routerReducer=connectRouter(history)
100-
exportconst[store]=newStoreBuilder<StoreState>()
106+
exportconst store=newStoreBuilder<StoreState>()
101107
.withMiddleware(routerMiddleware(history))
102108
.withReducer('router',routerReducer)
103109
.withDevTools()// enable chrome devtools
@@ -135,7 +141,7 @@ Create redux store with builder pattern.
135141
import {StoreBuilder }from'redux-ts'
136142
import {authReducer }from'./reducers/authReducer'
137143

138-
exportconst[store,mapStoreToProps]=newStoreBuilder<StoreState>()
144+
exportconst{ connected, mapStoreToProps,...store }=newStoreBuilder<StoreState>()
139145
.withInitialState({test:true})
140146
.withMiddleware()
141147
.withReducer("auth",authReducer)
@@ -147,6 +153,7 @@ export const [store, mapStoreToProps] = new StoreBuilder<StoreState>()
147153
- As generic parameter, it requires store state type in order to match given reducers and the state.
148154
- Any number of middleware, enhancer or reducer can be used to build the state.
149155
-`mapStoreToProps` is a dummy method that returns passed parameter again. This method can be used to map store object to props which are consumed from connected components. Return type is`MapStateToPropsParam` which is compatible with[connect](https://react-redux.js.org/api/connect).
156+
-`connected` function is also another dummy function that wraps original[connect](https://react-redux.js.org/api/connect) function but with implicit type resolution support. Problem with original one, when you connect your component with connect method, it is trying to resolve typing by matching signature you passed as parameters to connect_(mapStateToProps, mapDispatchToProps)_ and component own properties. If you are using explicit typing mostly, it is totally fine to use original one. But if you are expecting implicit type resolution, original connect is failing and resolving inner component type as`never`.
150157

151158
###Actions
152159

@@ -231,14 +238,17 @@ export const authReducer = new ReducerBuilder<AuthState>()
231238

232239
[connect](https://react-redux.js.org/api/connect) method is part of[react-redux](https://github.com/reduxjs/react-redux) library that allows you to connect your react components with redux store.
233240

241+
>You can use`connected` method for implicit type resolution.
242+
234243
```tsx
235244
import*asReactfrom'react'
236-
import {connect }from'react-redux'
237245
import {mapDispatchToProps }from'redux-ts'
238-
import {mapStoreToProps }from'../store'
246+
import {store }from'../store'
239247
import {ChangeTheme }from'../actions/layout.actions'
240248
import {Logout }from'../actions/auth.actions'
241249

250+
const { mapStoreToProps, connected }=store
251+
242252
// Map store object to component props
243253
const storeProps=mapStoreToProps(store=> ({
244254
useDarkTheme:!!store.layout.useDarkTheme
@@ -250,7 +260,7 @@ const dispatchProps = mapDispatchToProps({
250260
ChangeTheme
251261
})
252262

253-
exportconstLayout=connect(storeProps,dispatchProps)(({
263+
exportconst Layout=connected(storeProps,dispatchProps)(({
254264
children,// standard react prop
255265
useDarkTheme,// mapped store prop
256266
Logout,// mapped action prop

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name":"redux-ts",
3-
"version":"4.2.0-rc.3",
3+
"version":"4.2.0-rc.6",
44
"description":"Utils to define redux reducer/action in typescript",
55
"main":"dist/redux-ts.production.min.js",
66
"types":"lib/index.d.ts",
@@ -21,7 +21,7 @@
2121
"build:prod":"webpack --config webpack.prod.js",
2222
"clean":"rimraf dist lib",
2323
"build":"npm run clean && npm run build:dev && npm run build:prod",
24-
"prepublish":"npm run test && npm run build",
24+
"prepare":"npm run test && npm run build",
2525
"test":"mocha --require source-map-support/register --require ts-node/register tests/**/*.spec.ts"
2626
},
2727
"tags": [

‎src/helpers/redux.helpers.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{ActionCreatorDefinition,DispatchToProps,Indexer}from'..'
1+
import{ActionCreatorDefinition,DispatchToProps,Indexer}from'../'
22

33
exportconstcreateAction=<TPayload=any,TMeta=any>(
44
type:string,
@@ -35,4 +35,4 @@ export const mapDispatchToProps: DispatchToProps = map => (dispatch, own) => {
3535
)astypeofm
3636

3737
returntypeofmap==='function' ?mapper(map(dispatch,own)) :mapper(map)
38-
}
38+
}

‎src/models/redux.model.ts‎

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import{MapDispatchToPropsFunction,MapStateToProps}from'react-redux'
2-
import{AnyAction}from'redux'
1+
import{
2+
MapDispatchToPropsFunction,MapDispatchToPropsParam,MapStateToProps,MapStateToPropsParam
3+
}from'react-redux'
4+
import{AnyAction,StoreasReduxStore}from'redux'
5+
6+
exporttypeHOC<Pin,Pout>=(c:React.ComponentType<Pin>)=>React.ComponentType<Pout>
37

48
exporttypeIndexer<T=any>={[key:string]:T}
59

@@ -14,3 +18,39 @@ export type DispatchToProps = {
1418
map:T|MapDispatchToPropsFunction<T,TOwn>,
1519
):MapDispatchToPropsFunction<T,TOwn>
1620
}
21+
22+
exportinterfaceStore<StoreState>extendsReduxStore<StoreState>{
23+
/**
24+
* Dummy function to return `MapStateToProps` type that can be passed to `connect`
25+
* As paramter, mapper function is required which takes store object and returns indexer object
26+
* You can expose that function from your store object to be able to use on connected components.
27+
* ex.
28+
* export const [store, mapStoreToProps] = new StoreBuilder<StoreState>().build()
29+
*
30+
*@type {StateToProps<S>}
31+
*@memberof StoreBuilder
32+
*/
33+
mapStoreToProps:StateToProps<StoreState>
34+
35+
/**
36+
* Wrapper of redux connect method in order to support inferring props of inner component
37+
* ex.
38+
* export const [store, mapStoreToProps, connected] = new StoreBuilder<StoreState>().build()
39+
*
40+
*@private
41+
*@template TStateProps
42+
*@template TDispatchProps
43+
*@template TOwnProps
44+
*@template State
45+
*@param {MapStateToPropsParam<TStateProps, TOwnProps, State>} [mapStateToProps]
46+
*@param {MapDispatchToPropsParam<TDispatchProps, TOwnProps>} [mapDispatchToProps]
47+
*@returns {(HOC<
48+
* TStateProps & TDispatchProps & TOwnProps,
49+
* Exclude<TOwnProps, TStateProps & TDispatchProps>>)}
50+
*@memberof StoreBuilder
51+
*/
52+
connected<TStateProps={},TDispatchProps={},TOwnProps={}>(
53+
mapStateToProps?:MapStateToPropsParam<TStateProps,TOwnProps,StoreState>,
54+
mapDispatchToProps?:MapDispatchToPropsParam<TDispatchProps,TOwnProps>,
55+
):HOC<TStateProps&TDispatchProps&TOwnProps,Exclude<TOwnProps,TStateProps&TDispatchProps>>
56+
}

‎src/store.builder.ts‎

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1+
import{connect}from'react-redux'
12
import{
2-
applyMiddleware,
3-
combineReducers,
4-
compose,
5-
createStore,
6-
DeepPartial,
7-
Dispatch,
8-
Middleware,
9-
Reducer,
10-
ReducersMapObject,
11-
Store,
12-
StoreEnhancer,
3+
applyMiddleware,combineReducers,compose,createStore,DeepPartial,Dispatch,Middleware,
4+
Reducer,ReducersMapObject,StoreEnhancer
135
}from'redux'
146

15-
import{Action,ReducerBuilder,StateToProps}from'.'
7+
import{Action,ReducerBuilder,StateToProps,Store}from'./'
168

179
constdevTool:StoreEnhancer=f=>
1810
(windowasany).__REDUX_DEVTOOLS_EXTENSION__||f
@@ -143,26 +135,13 @@ export class StoreBuilder<S extends StoreState> {
143135
returnthis
144136
}
145137

146-
/**
147-
* Dummy function to return `MapStateToProps` type that can be passed to `connect`
148-
* As paramter, mapper function is required which takes store object and returns indexer object
149-
* You can expose that function from your store object to be able to use on connected components.
150-
* ex.
151-
* const [store, mapStoreToProps] = new StoreBuilder<StoreState>().build()
152-
* export { mapStoreToProps }
153-
*
154-
*@type {StateToProps<S>}
155-
*@memberof StoreBuilder
156-
*/
157-
privatemapStoreToProps:StateToProps<S>=map=>map
158-
159138
/**
160139
* Build an instance of store with configured values.
161140
*
162141
*@returns {Store<StoreType>}
163142
*@memberof StoreBuilder
164143
*/
165-
publicbuild():[Store<S>,StateToProps<S>]{
144+
publicbuild():Store<S>{
166145
constdefer=Promise.defer<Dispatch<Action>>()
167146
constreducerMap=Object.keys(this.reducerBuilders).reduce(
168147
(p:any,r)=>({
@@ -178,6 +157,13 @@ export class StoreBuilder<S extends StoreState> {
178157

179158
defer.resolve(store.dispatch)
180159

181-
return[store,this.mapStoreToProps]
160+
return{
161+
...store,
162+
mapStoreToProps:map=>map,
163+
connected:(mapStateToProps,mapDispatchToProps)=>mapDispatchToProps
164+
?(connect(mapStateToProps,mapDispatchToProps)asany)
165+
:(connect(mapStateToProps)asany)
166+
167+
}
182168
}
183169
}

‎tests/reducer.builder.spec.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('Reducer', () => {
2424
isBasicActionCalled:true,
2525
})
2626

27-
const[store]=newStoreBuilder<StoreState>()
27+
conststore=newStoreBuilder<StoreState>()
2828
.withReducerBuildersMap({ reducer})
2929
.build()
3030

@@ -41,7 +41,7 @@ describe('Reducer', () => {
4141
returnstate
4242
})
4343

44-
const[store]=newStoreBuilder<StoreState>()
44+
conststore=newStoreBuilder<StoreState>()
4545
.withReducerBuilder('reducer',reducer)
4646
.build()
4747

@@ -84,7 +84,7 @@ describe('Reducer', () => {
8484
returnnext(a)
8585
})
8686
.withReducerBuildersMap({ reducer})
87-
.build()[0]
87+
.build()
8888

8989
store.dispatch(SimpleAction())
9090
})

‎tests/store.builder.spec.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('Store', () => {
1313
constinitState={reducer:{test:true}}
1414

1515
describe('with initial state',()=>{
16-
const[store]=newStoreBuilder()
16+
conststore=newStoreBuilder()
1717
.withInitialState(initState)
1818
.withReducersMap({ reducer})
1919
.build()
@@ -29,7 +29,7 @@ describe('Store', () => {
2929
isSet=true
3030
returnnext(action)
3131
}
32-
const[store]=newStoreBuilder()
32+
conststore=newStoreBuilder()
3333
.withMiddleware(testMiddleware)
3434
.withReducersMap({ reducer})
3535
.build()
@@ -49,7 +49,7 @@ describe('Store', () => {
4949
}
5050
returnstate
5151
}
52-
const[store]=newStoreBuilder().withReducer('test',testReducer).build()
52+
conststore=newStoreBuilder().withReducer('test',testReducer).build()
5353

5454
store.dispatch(testAction)
5555

@@ -66,7 +66,7 @@ describe('Store', () => {
6666
}
6767
returnstate
6868
}
69-
const[store]=newStoreBuilder().withReducersMap({ testReducer}).build()
69+
conststore=newStoreBuilder().withReducersMap({ testReducer}).build()
7070

7171
store.dispatch(testAction)
7272

@@ -81,7 +81,7 @@ describe('Store', () => {
8181
isSet=true
8282
returnf
8383
}
84-
const[store]=newStoreBuilder()
84+
conststore=newStoreBuilder()
8585
.withReducersMap({ reducer})
8686
.withEnhancer(enhancer)
8787
.build()

‎tsconfig.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"outDir":"./lib",
99
"lib": ["dom","es5","es2015.promise","es2015.core"]
1010
},
11-
"exclude": ["node_modules","tests"]
11+
"exclude": ["node_modules","tests","lib","dist"]
1212
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp