Reuse your store logic
Heridux was created primarily to make redux stores reusable (just like hooks make internal states reusable).
For example, in a large application, you can have several CRUDs that work according to the same logic, but with redux it is difficult to share this code (even if it's a bit easier with Redux Toolkit).
MyStore.js
import Heridux from "@heridux/immer"
export default class MyStore extends Heridux {
constructor(STATE_PROPERTY) {
super(STATE_PROPERTY)
this.setInitialState({ count : 0 })
this.createAction("increment", state => {
state.count++
})
}
}
store1.js
import Store from "./MyStore"
const store = new MyStore("my first store")
// register in redux store
// with "my first store" as entry key
store.register()
store.execAction("increment")
store2.js
import Store from "./MyStore"
const store = new MyStore("my second store")
// create additional actions if you need
store.createAction("decrement", state => {
state.count--
})
store.register()
store.execAction("increment")
store.execAction("decrement")
No more hesitation between state and redux
It is sometimes difficult to know in advance whether the state should be stored in the redux store or whether an internal state is sufficient.
With heridux, no more worries : the API is unique, you can choose afterwards whether you want to use redux or an internal state.
With Redux
import Heridux from "@heridux/immer"
const store = new Heridux("entryKey")
store.createAction("increment", state => { state.count++ })
store.register()
export default store
With internal state
import Heridux from "@heridux/immer"
const store = new Heridux() // entry key is not needed
store.createAction("increment", state => { state.count++ })
// don't register in redux store and that's all !
export default store
Easy to use with Immer or Immutable
Even if you don't have to, it is strongly recommended to use the Immer version of Heridux. Alternatively, you can also use the Immutable version of Heridux.
Without ImmerJS or ImmutableJS
import Heridux from "@heridux/core"
const store = new Heridux("entryKey")
store.setInitalState({
address : { zipCode : "31400", city : "Toulouse" }
})
store.createAction("changeZipCode", (state, { zipCode }) => ({
...state,
address : {
...state.address,
zipCode
}
}))
With ImmerJS
import Heridux from "@heridux/immer"
const store = new Heridux("entryKey")
store.setInitalState({
address : { zipCode : "31400", city : "Toulouse" }
})
store.createAction("changeZipCode", (state, { zipCode }) => {
state.address.zipCode = zipCode
})
With ImmutableJS
import Heridux from "@heridux/immutable"
const store = new Heridux("entryKey")
store.setInitalState({
address : { zipCode : "31400", city : "Toulouse" }
})
store.createAction("changeZipCode", (state, { zipCode }) => (
state.setIn(["address", "city"], zipCode)
))
No learning pain
The API is minimalist and mostly the same as React-Redux.
Getting started
Installation
npm install @heridux/core @heridux/immer @heridux/react
# or with yarn
yarn add @heridux/core @heridux/immer @heridux/react
Setting up
With redux from scratch
import Heridux from "@heridux/immer"
import { Provider } from "react-redux"
import App from "./App"
// with Heridux you'll define your reducers later
const reduxStore = Heridux.createReduxStore()
export default () => (
<Provider store={ reduxStore }>
<App/>
</Provider>
)
With an existing redux store
import { createStore } from "redux"
import Heridux from "@heridux/immer"
const reducers = function(state){ /* redux reducer */ return state }
const store = createStore(reducers)
Heridux.connect(store, reducers)
export default store
Without redux
If you don't plan to use redux (maybe you should) but only internal states, nothing is required here.
Using Heridux
store.js
import Heridux from "@heridux/immer"
const store = new Store("counter")
store.setInitialState({ counter : 0 })
store.createAction("increment", state => {
state.counter++
})
store.createAction("decrement", state => {
state.counter--
})
store.register() // omit this line if you don't want to store your data in redux
// but only in an internal state
export default store
AppPart.js
import { Provider } from "@heridux/react"
import store from "./store"
import MyComponent from "./MyComponent"
export default () => (
<Provider store={ store }>
<MyComponent/>
</Provider>
)
MyComponent.js
import { useStore, useSelector } from "@heridux/react"
const MyComponent = () => {
const store = useStore()
const counter = useSelector(state => state.counter)
return (
<div>
<p>Clicked: <span>{ counter }</span> times</p>
<button onClick={ () => store.execAction("increment") }>+</button>
<button onClick={ () => store.execAction("decrement") }>-</button>
</div>
)
}
Alternatively, you can use a HOC
import { connect } from "@heridux/react"
const MyComponent = ({ store, counter }) => (
<div>
<p>Clicked: <span>{ counter }</span> times</p>
<button onClick={ () => store.execAction("increment") }>+</button>
<button onClick={ () => store.execAction("decrement") }>-</button>
</div>
)
const mapStateToProps = state => ({
counter : state.counter
})
export default connect(mapStateToProps)(MyComponent)
FAQ
Why do I get the error "Redux store has not been defined as reduxStore key of Heridux" ?
Make sure Heridux is connected to Redux before importing any file that uses it. You'll probably have to create a separate file, like in this example.