This repository has been archived by the owner on Jul 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
110 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,139 @@ | ||
## Stencil Redux | ||
|
||
A simple redux connector for Stencil-built web components inspired by react-redux. | ||
A simple redux connector for Stencil-built web components inspired by [`react-redux`](https://github.com/reduxjs/react-redux). | ||
|
||
## Install | ||
|
||
``` | ||
npm install @stencil/redux | ||
npm install redux | ||
npm install -D @types/redux | ||
``` | ||
|
||
## Usage | ||
|
||
Stencil Redux uses the official redux library underneath, so much of the creation and configuration of the store, along with specifying reducers and middleware, is identical. | ||
Stencil Redux uses the [`redux`](https://github.com/reduxjs/redux/) library underneath. Setting up the store and defining actions, reducers, selectors, etc. should be familiar to you if you've used React with Redux. | ||
|
||
### Configure store | ||
### Configure the Root Reducer | ||
|
||
```typescript | ||
// src/store/index.ts | ||
import { createStore, applyMiddleware } from 'redux'; | ||
import thunk from 'redux-thunk'; // Add-on you might want | ||
import logger from 'redux-logger'; // Add-on you might want | ||
import rootReducer from '../reducers/index'; | ||
// redux/reducers.ts | ||
|
||
import { combineReducers } from 'redux'; | ||
|
||
// Import feature reducers and state interfaces. | ||
import { TodoState, todos } from './todos/reducers'; | ||
|
||
const configureStore = (preloadedState: any) => | ||
createStore(rootReducer, preloadedState, applyMiddleware(thunk, logger)); | ||
// This interface represents app state by nesting feature states. | ||
export interface RootState { | ||
todos: TodoState; | ||
} | ||
|
||
export { configureStore }; | ||
// Combine feature reducers into a single root reducer | ||
export const rootReducer = combineReducers({ | ||
todos, | ||
}); | ||
``` | ||
|
||
### Configure reducers | ||
### Configure the Actions | ||
|
||
```typescript | ||
// src/reducers/index.ts | ||
import myReducer from './myReducer'; | ||
// redux/actions.ts | ||
|
||
import { combineReducers } from 'redux'; | ||
import { RootState } from './reducers'; | ||
|
||
const rootReducer = (combineReducers as any)({ | ||
myReducer | ||
}); | ||
|
||
export default rootReducer; | ||
// Import feature action interfaces | ||
import { TodoAction } from './todos/actions'; | ||
|
||
// Export all feature actions for easier access. | ||
export * from './todos/actions'; | ||
|
||
// Combine feature action interfaces into a base type. Use union types to | ||
// combine feature interfaces. | ||
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types | ||
export type Action = ( | ||
TodoAction | ||
); | ||
``` | ||
|
||
### Configure the Store | ||
|
||
```typescript | ||
// redux/store.ts | ||
|
||
import { Store, applyMiddleware, createStore } from 'redux'; | ||
import thunk from 'redux-thunk'; // add-on you may want | ||
import logger from 'redux-logger'; // add-on you may want | ||
|
||
import { RootState, rootReducer } from './reducers'; | ||
|
||
export const store: Store<RootState> = createStore(rootReducer, applyMiddleware(thunk, logger)); | ||
``` | ||
|
||
### Configure Store in Root Component | ||
|
||
```typescript | ||
|
||
// components/my-app/my-app.tsx | ||
|
||
import { Store } from '@stencil/redux'; | ||
import { configureStore } from '../../store/index'; // index required due to bug | ||
|
||
import { Action } from '../../redux/actions'; | ||
import { RootState } from '../../redux/reducers'; | ||
import { store } from '../../redux/store'; | ||
|
||
@Component({ | ||
tag: 'my-app', | ||
styleUrl: 'my-app.scss' | ||
}) | ||
export class MyApp { | ||
@Prop({ context: 'store' }) store: Store; | ||
@Prop({ context: 'store' }) store: Store<RootState, Action>; | ||
|
||
componentWillLoad() { | ||
this.store.setStore(configureStore({})); | ||
this.store.setStore(store); | ||
} | ||
} | ||
``` | ||
|
||
### Map state and dispatch to props | ||
|
||
:memo: *Note*: Because the mapped props are technically changed *within* the component, `mutable: true` is required for `@Prop` definitions that utilize the store. See the [Stencil docs](https://stenciljs.com/docs/properties#prop-value-mutability) for info. | ||
|
||
```typescript | ||
import { Store, Action } from '@stencil/redux'; | ||
// components/my-component/my-component.tsx | ||
|
||
import { Store, Unsubscribe } from '@stencil/redux'; | ||
|
||
import { Action, changeName } from '../../redux/actions'; | ||
import { RootState } from '../../redux/reducers'; | ||
|
||
@Component({ | ||
tag: 'my-component', | ||
styleUrl: 'my-component.scss' | ||
}) | ||
export class MyComponent { | ||
@Prop({ context: 'store' }) store: Store; | ||
|
||
@State() name: string; | ||
|
||
changeName: Action; | ||
|
||
private unsubscribe: () => void; | ||
|
||
@Prop({ context: 'store' }) store: Store<Action, RootState>; | ||
@Prop({ mutable: true }) name: string; | ||
|
||
changeName!: typeof changeName; | ||
|
||
unsubscribe!: Unsubscribe; | ||
|
||
componentWillLoad() { | ||
this.unsubscribe = this.store.mapStateToProps(this, (state) => { | ||
const { | ||
myReducer: { name } | ||
} = state; | ||
return { | ||
name | ||
} | ||
this.unsubscribe = this.store.mapStateToProps(this, state => { | ||
const { user: { name } } = state; | ||
return { name }; | ||
}); | ||
|
||
this.store.mapDispatchToProps(this, { | ||
changeName | ||
}); | ||
} | ||
|
||
doNameChange(newName: string) { | ||
this.changeName(newName); | ||
|
||
this.store.mapDispatchToProps(this, { changeName }); | ||
} | ||
|
||
componentDidUnload() { | ||
this.unsubscribe(); | ||
} | ||
|
||
doNameChange(newName: string) { | ||
this.changeName(newName); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,16 @@ | ||
export interface Store { | ||
dispatch: (action: any, _: any) => any; | ||
subscribe: (cb: (...args: any[]) => any) => any; | ||
getState: () => any; | ||
getStore: () => any; | ||
setStore: (store: any) => void; | ||
mapStateToProps: (component: any, props: any) => () => void; | ||
mapDispatchToProps: (component: any, props: any) => void; | ||
import { Action, AnyAction, Store as ReduxStore, Unsubscribe } from 'redux'; | ||
|
||
export interface Store<S = any, A extends Action = AnyAction> { | ||
getState: () => S; | ||
getStore: () => ReduxStore<S, A>; | ||
setStore: (store: ReduxStore<S, A>) => void; | ||
mapStateToProps: <C extends R, R>(component: C, mapper: (state: S) => R) => Unsubscribe; | ||
mapDispatchToProps: <C extends P, P>(component: C, props: P) => void; | ||
} | ||
|
||
/** | ||
* @deprecated See README.md for new usage. | ||
*/ | ||
export type Action = (...args: any[]) => any; | ||
|
||
export { Unsubscribe }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1 @@ | ||
export { | ||
Store, | ||
Action, | ||
} from './global/interfaces'; | ||
export * from './global/interfaces'; |