Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/esamattis/redux-render-prop
Redux with render props. Typescript friendly.
https://github.com/esamattis/redux-render-prop
reactjs redux typescript
Last synced: 24 days ago
JSON representation
Redux with render props. Typescript friendly.
- Host: GitHub
- URL: https://github.com/esamattis/redux-render-prop
- Owner: esamattis
- License: mit
- Created: 2018-06-06T18:53:53.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2019-09-12T20:38:47.000Z (about 5 years ago)
- Last Synced: 2024-09-26T13:07:16.131Z (about 1 month ago)
- Topics: reactjs, redux, typescript
- Language: TypeScript
- Homepage: http://npmjs.com/package/redux-render-prop
- Size: 269 KB
- Stars: 22
- Watchers: 4
- Forks: 0
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# redux-render-prop
[![Greenkeeper badge](https://badges.greenkeeper.io/epeli/redux-render-prop.svg)](https://greenkeeper.io/)
Redux with [render props][1]. Alternative to the `connect()` higher order component.
Read an introductory [blog post here](https://medium.com/@esamatti/type-safe-boilerplate-free-redux-906844ec6325).
[1]: https://reactjs.org/docs/render-props.html
Very TypeScript friendly. It heavily leverages type inference to
avoid manual typing of props.## Install
For react-redux 6.x
```sh
npm install redux-render-prop react-redux@6 # has peer dep of react-redux 6.x
```For react-redux 5.x you must use pre 0.7 versions
```sh
npm install [email protected] react-redux@5 # has peer dep of react-redux 5.x
```For Typescript you will need the types too
```sh
npm install @types/react-dom @types/react @types/react-redux
```## Usage
```ts
import {makeConnector} from "redux-render-prop";
import {bindActionCreators} from "redux";// Define state as a single type
interface State {
counters: {
[name: string]: {count: number};
};
}// Define some actions creators
const ActionCreators = {
incrementByName: (name: string) => {
return {type: "INC", name};
},
};// Create render prop component creator with app specific types.
// There is usually only one of these per app
const createAppConnect = makeConnector({
// Component creators infer the state type from here.
//
// It is possible to return only part of the state here
// which can be handy if you have a large app and want multiple
// more specific component creators.
//
// You can also return here something other than the state
// itself. For example you could wrap it with selector helpers.
prepareState: (state: State) => state,// Actions are prepared similarly.
prepareActions: dispatch => bindActionCreators(ActionCreators, dispatch),
});// Create render prop component for counters.
const CounterConnect = createAppConnect({
// State type is infered from the prepareState return value
mapState: (state, ownProps: {name: string}) => ({
count: state.counters[ownProps.name].count,
}),// Actions type is infered from the prepareActions and
// ownProps type is from the mapState ownProps
mapActions: (actions, ownProps) => ({
inc() {
actions.incrementByName(ownProps.name);
},
}),
});// Must be wrapped with
const App = () => (
{(data, actions) => (
// Fully typed data and actions
{data.count}
)}
);
```## Flattening render props
If you find yourself nesting too much you can flatten the render callbacks
type safely with the `MappedState`, `MappedActions` and
`MappedStateAndActions` type helpers like so:```tsx
import {MappedState, MappedActions} from "redux-render-prop";class MyComponent {
renderCounter(
data: MappedState,
actions: MappedActions,
) {
return {data.count};
}render() {
return {this.renderCounter};
}
}
```You can also use it to pass the props to class components if you need to access
the mapped state or actions from lifecycle methods.```tsx
class ClassComponent extends React.Component<
MappedStateAndActions
> {
componentDidMount() {
// do something with this.props.count
}render() {
return{this.props.count};
}
}export default () => (
{data => }
);
```## Memoizing
For advanced high performance you may use `memoizeMapState()` to
create memoized selectors on component mount.```tsx
const FooConnect = createComponent({
// The initialState is the state at the time of the component
// mount and it won't change during the component lifetime.
// Same goes for the initialOwnProps.
memoizeMapState: (initialState, initialOwnProps) => {
// using the reselect module
const selectFoosOnly = createSelector(
(s: typeof initialState) => s.list,
list =>
list.map(obj => ({
foo: obj.foo,
})),
);// Return the actual mapState function
return (state, ownProps) => {
return {
foos: selectFoosOnly(state),
};
};
},
});
```## Examples
Here's a more complete example with [immer-reducer](https://github.com/epeli/immer-reducer):