react-send-action
v0.2.1
Published
react-send-action is a small library that hook up a `send-action` store into your React app, works not unlike react-redux
Downloads
8
Readme
react-send-action
react-send-action is a small library that hook up a send-action
store into your React app, works not unlike react-redux.
Installation
$ npm i react-send-action --save
What is send-action
send-action
is meant to be the smallest, simplest redux-like state management library. The focus is on providing a concise method for triggering actions, and on avoiding complex middleware & development dependencies.
The API is significantly different from
redux
, but the pattern is similar.
Using
send-action
you trigger actions, modify state based on those actions, and listen to the changes to render your application.
API
<Provider createStore={createStore}>
Makes the send-action
store available to the connect()
calls in the component hierarchy below. Normally, you can’t use connect()
without wrapping the root component in <Provider>
.
Connect(mapProps, mapActionHandlers, mapStatics)(Component)
Connects a React component to a send-action
store.
It does not modify the component class passed to it. Instead, it returns a new, connected component class, for you to use.
Usage
TLDR:
Container component: select props
and actionHandler
to Container.
import React, { PropTypes } from 'react'
import { Connect } from 'react-send-action'
import App from './app'
// select user from store
export default Connect(
(store, props) => {
let { user } = store.state()
return {
user
}
},
(store, props) => {
let { user } = store.state()
return {
user
}
}
)(App)
Root of the app: hook store in to the app.
import React from 'react'
import { render } from 'react-dom'
import Provider from '../'
import AppContainer from './appContainer'
import initialState from './initialState'
import actionHandler from './actionHandler'
const createStore = {
actionHandler,
initialState
}
render((
<Provider createStore={createStore}>
<AppContainer />
</Provider>
), document.body)
Longer version
Prepare actionHandler
and initialState
that will be used to createStore
- Create
initialState
for your whole application
const initialState = {
user: {
name: 'fraserxu'
}
}
export default initialState
- Create a
actionHandler.js
to trigger changes action and reduce new State
/**
* Store action handler
* @param {Object} action Object
* @param {Object} state Object
* @return {Object} new State
*/
export default function onaction (action, state) {
switch (action.type) {
case 'updateUser':
const { user } = action.payload
return {
...state,
user
}
}
}
Hook your createStore
object to the Provider
, this step does two things:
- Create a
store
object on the Appcontext
, so yourchild
orgrand-child
component could have access to the store viathis.context.store
- Hook the
onchange
event to theProvider
component itself so it could update the internal state and cause the app to do a re-render
Provider
works on both client side and server side. To hook the store to your app, you can do:
Provider(client side)
import { Provider } from 'react-send-action'
import React from 'react'
import { render } from 'react-dom'
import AppContainer from './appContainer'
import initialState from './initialState'
import actionHandler from './actionHandler'
const createStore = {
actionHandler,
initialState
}
render((
<Provider createStore={createStore}>
<AppContainer />
</Provider>
), document.body)
Provider(server side)
renderToString(
<Provider createStore={createStore}>
<AppContainer />
</Provider>
)
There are three way to consume state
and dispatch action
in your child componet.
First way is to access to store
object directly from this.context.store
, which is not recommended as
Using context makes your components more coupled and less reusable, because they behave differently depending on where they're rendered.
import React from 'react'
class App extends React.Component {
onClickHandler () {
// dispatch an toggle event
this.context.store(
'type': 'updateUser',
'payload': {
name: 'someone else'
}
)
}
render () {
const { user } = this.context.store.state()
return (
<div>
<span>{user.name}</span>
<button onClick={this.onClickHandler}>Toggle</button>
</div>
)
}
}
App.contextTypes = {
store: React.PropTypes.func.isRequired
}
export default App
The other way to use it is through container component
. There are lots of reasons to use container component, the most obvious one is to seperate the data logic from your view component, most of your view should be dumb
and only takes in props and render the view, so it's very easy to test and reuse.
You should always only handle your data logic inside the high order component, and pass down the state
and dispatchers
down through props
.
First presume we have a dump home page component
import React, { PropTypes } from 'react'
class App extends React.Component {
static propTypes = {
user: PropTypes.object
}
render () {
const { user } = this.props
return (
<span>{user.name}</span>
)
}
}
export default App
And then we use the a helper function to grab the user
props from our store
import React, { PropTypes } from 'react'
import App from './app'
class AppContainer extends React.Component {
render () {
let { user } = this.context.store.state()
return (
<HomePage user={user} />
)
}
}
AppContainer.contextTypes = {
store: PropTypes.func.isRequired
}
export default AppContainer
For more details, please check the example
directory.
The last way and easiest way is to use the builtin Connect
component which hook up the props
, actionsHandlers
and static
method to the wrappedComponent.
import React from 'react'
import { Connect } from 'react-send-action'
import App from './app'
import { fetchStats } from './common/utils/api'
const AppContainer = Connect(
(store, props) => {
const { user, stats } = store.state()
return {
user,
stats
}
},
(store, props) => {
return {
setUser: (user) => {
store({
type: 'userSignedIn',
payload: {
user
}
})
}
}
},
{
actions: {
stats: fetchStats
}
}
)(App)
export default AppContainer
License
MIT