Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

merdux

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

merdux - npm Package Compare versions

Comparing version 0.1.1 to 0.1.3

2

build/interfaces.d.ts

@@ -57,2 +57,2 @@ import { MapDispatchToPropsNonObject, MapDispatchToPropsParam, ResolveThunks } from 'react-redux';

};
export declare type IConnectProps<mapStateToProps extends (state: IRootState) => any, mapDispatchToProps extends MapDispatchToPropsParam<any, any> | MapDispatchToPropsNonObject<any, any>> = ReturnType<mapStateToProps> & (mapDispatchToProps extends MapDispatchToPropsNonObject<infer TDispatchProps, any> ? TDispatchProps : ResolveThunks<mapDispatchToProps>);
export declare type IConnectProps<mapStateToProps extends (state: IRootState) => any = () => {}, mapDispatchToProps extends MapDispatchToPropsParam<any, any> | MapDispatchToPropsNonObject<any, any> = {}> = ReturnType<mapStateToProps> & (mapDispatchToProps extends MapDispatchToPropsNonObject<infer TDispatchProps, any> ? TDispatchProps : ResolveThunks<mapDispatchToProps>);
{
"name": "merdux",
"version": "0.1.1",
"version": "0.1.3",
"description": "Opinionated redux abstraction to manage stores more easily",

@@ -16,2 +16,3 @@ "keywords": [

},
"homepage": "https://github.com/lonestone/merdux/blob/master/packages/merdux/README.md",
"main": "build/index.js",

@@ -18,0 +19,0 @@ "types": "build/index.d.ts",

# merdux
> An insult to redux, making it tolerable
## Table of contents
- [What is merdux, and why?](#What-is-merdux-and-why)
- [Install](#install)
- [Usage](#usage)
- [Initial state](#initial-state)
- [Effects](#effects)
- [Prepare Store](#prepare-store)
- [Add to redux store](#add-to-redux-store)
- [Connect to React components](#connect-to-react-components)
- [React hooks](#react-hooks)
- [Know drawbacks](#know-drawbacks)
- [Author](#author)
- [License](#license)
## What is merdux, and why?
Merdux is an opinionated [**redux**](https://redux.js.org/) abstraction, hacking the way reducers and actions work to provide an easier solution to write a redux store.
Redux is great, but their should be an easier way to manage most stores, without compromise.
With merdux, actions and reducers are replaced by **effects**.
Merdux is composable with classic actions, reducers and middlewares (thunk, saga, etc). Integration into existing architecture should be a breeze.
- Fully typed
- Ultra lightweight
- Hooks and types provided for use with react-redux
_All examples here are in TypeScript, but you can use Javascript by removing types._
## Install
```bash
npm install merdux redux redux-thunk
```
## Usage
A store is made of an initial state and effects. Merdux provides functions to prepare stores from them and give them to redux.
### Initial state
Example of the initial state of a counter:
```ts
interface IState {
readonly count: number
readonly counting: boolean
}
const initialState: IState = {
count: 0,
counting: false
}
```
### Effects
In merdux, an effect provides one or more partial states to modify the state of redux, and can execute asynchronous side effects (API calls, delay).
A **state transform** is either a partial state or a function transforming the current state to a new partial state.
```ts
type StateTransform<State> = Partial<State> | ((state: State) => Partial<State>)
```
**An effect is a function**, possibly with argument, that **return a state transform** or an **async generator** of state transforms.
```ts
type Effect<State, Params extends []> = (
this: State,
...params: Params
) => StateTransform<State> | AsyncIterableIterator<StateTransform<State>>
```
Example of effects for our counter:
```ts
{
// Function that return a new partial state
reset: () => ({ count: 0 }),
// Function that return a state transform
increment: () => state => ({ count: state.count + 1 }),
// with an argument
decrement: (n: number) => state => ({ count: state.count - n }),
// Async generator that yields state transforms
async *incrementAsync() {
// Accessing current state
console.log('count', this.count)
// New partial state
yield { counting: true }
// Add 5 times 1 with delay
for (let i = 1; i <= 5; i++) {
// New partial state from current state
yield state => ({ count: state.count + 1 })
await new Promise(resolve => setTimeout(resolve, 500))
}
yield { counting: false }
}
}
```
### Prepare Store
Each store can be contained in a single file using the method `prepareStore`.
Example of `counter.ts`:
```ts
import { prepareStore } from 'merdux'
interface IState {
readonly count: number
readonly counting: boolean
}
const initialState: IState = {
count: 0,
counting: false
}
export default prepareStore(initialState, {
reset: () => ({ count: 0 }),
increment: () => state => ({ count: state.count + 1 }),
decrement: (n: number) => state => ({ count: state.count - n }),
async *incrementAsync() {
console.log('count', this.count)
yield { counting: true }
for (let i = 1; i <= 5; i++) {
yield state => ({ count: state.count + 1 })
await new Promise(resolve => setTimeout(resolve, 500))
}
yield { counting: false }
}
})
```
### Add to redux store
Merdux is meant to be used with [**redux**](https://redux.js.org/) and [**redux-thunk**](https://github.com/reduxjs/redux-thunk).
Use the method `combineStores` from merdux to generate root initial state, reducers and actions from prepared stores.
- `initialState`: useful to get typing of root state
- `reducers`: can be merged with classic reducers and used with `combineReducers`
- `actions`: all actions, can be used with `mapDispatchToProps` or `dispatch`
```ts
import { combineStores } from 'merdux'
import { applyMiddleware, combineReducers, createStore } from 'redux'
import thunk from 'redux-thunk'
import counter from './counter'
import pokemons from './pokemons'
export const { reducers, actions, initialState } = combineStores({
// Prepared stores
counter,
pokemons
})
// Obtain and export full type of the root state
export type IRootState = typeof initialState
export default createStore(combineReducers(reducers), applyMiddleware(thunk))
```
## Connect to React components
You can connect your store as usual.
Import from the store file:
- `actions`: access them by namespace. eg: `actions.counter.increment`
- `IRootState`: type of the whole store, useful in `mapStateToProps`
Import from merdux:
- `IConnectProps`: useful to type props coming from redux
Example of `Counter.tsx`:
```tsx
import { IConnectProps } from 'merdux'
import React from 'react'
import { connect } from 'react-redux'
import { actions, IRootState } from '../store'
type IProps = IConnectProps<typeof mapStateToProps, typeof mapDispatchToProps>
class Counter extends React.Component<IProps> {
public render() {
const { count, counting, reset, increment, incrementAsync, decrement } = this.props
return (
<div>
<p>Count: {count}</p>
<button onClick={reset}>✖</button>
<button onClick={() => decrement(3)}>➖3</button>
<button onClick={() => decrement(1)}>➖</button>
<button onClick={increment}>➕</button>
<button onClick={incrementAsync}>➕5{counting && '⏳'}</button>
</div>
)
}
}
const mapStateToProps = ({ counter }: IRootState) => ({ ...counter })
const mapDispatchToProps = actions.counter
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter)
```
## React hooks
Merdux provides hooks with the package `merdux-hooks`.
It uses [`redux-react-hook`](https://github.com/facebookincubator/redux-react-hook) under the hood and exports all of its exports.
Install it in your project:
```bash
npm install merdux-hooks
```
To use hooks, you need to provide the store to the StoreContext:
```tsx
import { StoreContext } from 'merdux-hooks'
import React from 'react'
import store from '../store'
import Counter from './Counter'
export default function App() {
return (
<StoreContext.Provider value={store}>
<Counter />
</StoreContext.Provider>
)
}
```
Example of `Counter.tsx`, same as Counter above but with hooks:
```tsx
import { useActions, useMappedState } from 'merdux-hooks'
import React from 'react'
import { actions, IRootState } from '../store'
export default function Counter() {
const { count, counting } = useMappedState((state: IRootState) => state.counter)
const { reset, increment, incrementAsync, decrement } = useActions(actions.counter)
return (
<div>
<p>Count: {count}</p>
<button onClick={reset}>✖</button>
<button onClick={() => decrement(3)}>➖3</button>
<button onClick={() => decrement(1)}>➖</button>
<button onClick={increment}>➕</button>
<button onClick={incrementAsync)}>
➕5{counting && '⏳'}
</button>
</div>
)
}
```
## Know drawbacks
- Actions are isolated to their local stores and cannot be intercepted by other reducers. To do the latter, you can use good old Redux actions and reducers.
## Author
Godefroy de Compreignac - [Lone Stone](https://lonestone.studio)
## License
MIT
Migrated to [redux-zap](https://www.npmjs.com/package/redux-zap)

@@ -121,6 +121,6 @@ import {

export type IConnectProps<
mapStateToProps extends (state: IRootState) => any,
mapStateToProps extends (state: IRootState) => any = () => {},
mapDispatchToProps extends
| MapDispatchToPropsParam<any, any>
| MapDispatchToPropsNonObject<any, any>
| MapDispatchToPropsNonObject<any, any> = {}
> = ReturnType<mapStateToProps> &

@@ -127,0 +127,0 @@ (mapDispatchToProps extends MapDispatchToPropsNonObject<infer TDispatchProps, any>

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc