へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)! #vZkt8fc6J

Re-Mixing verbose Actions, Action Creators, dispatching codes in Component, and switching codes in Reducer.

Re-mixing verbose Actions, Action Creators, dispatching codes in Component, and switching codes in Reducer.

When we usually change the state of the store of Redux with React, we write Action, Action Creator, connect them with Container Component, then write codes in reducer.

This way is beautiful and it turns more clear than we struggled in the callback hell before, however it's too long to write. That makes us not enjoy it :(

Even if I want to change some trivial states, I should create an action, an action creator, add some changes in the component, then write codes only to change the state.

The following is the example.

actions.js

import createTypes from 'redux-create-action-types'
export const AT = createTypes('CLICK1', 'CLICK2', 'CLICK3')

action_creators.js

import { AT } from './actions'
export const click1 = () => ({ type: AT.CLICK1 })
export const click2 = () => ({ type: AT.CLICK2 })
export const click3 = () => ({ type: AT.CLICK3 })

the part of reducer.js

switch (action.type) {
  case CLICK1: {
    return Object.assign({}, state, { click1IsClicked: !state.click1IsClicked })
  }
  case CLICK2: {
    return Object.assign({}, state, { click2IsClicked: !state.click2IsClicked })
  }
  case CLICK3: {
    return Object.assign({}, state, { click3IsClicked: !state.click3IsClicked })
  }
}

the part of App.js

import { CLICK1, CLICK2, CLICK3 } from './action_creators'

~~~
const Heavy = ({ click1, click2, click3, reducer }) => (
  <div>
    <button onClick={e => click1()}>Button 1</button>
    <button onClick={e => click2()}>Button 2</button>
    <button onClick={e => click3()}>Button 3</button>
    {Object.keys(reducer).map(s => { if(reducer[s]) return <div key={s}>{s}</div>})}
  </div>
)

~~~
const mapDispatchToProps = {
  click1, click2, click3
}

Is there a need to write codes as such verbosely? Can I make it shorter?

Yes I've done it. Isn't it more clear than that?

import { dispactreducer } from './dispactreducer'

~~~
const Heavy = ({ dispactreducer, reducer }) => (
    <div>
      <button onClick={e => { dispactreducer('reducer', { button1IsClicked: !reducer.button1IsClicked }) }}>Button 1</button>
      <button onClick={e => { dispactreducer('reducer', { button2IsClicked: !reducer.button2IsClicked }) }}>Button 2</button>
      <button onClick={e => { dispactreducer('reducer', { button3IsClicked: !reducer.button3IsClicked }) }}>Button 3</button>
      {Object.keys(reducer).map(s => { if(reducer[s]) return <div key={s}>{s}</div>})}
    </div>
)

~~~
const mapDispatchToProps = {
  dispactreducer
}

This totally equals every codes I mentioned the above, the former codes.

This dispactreducer means dispatch + action creator + reducer.

That is why I use them while writing tiny codes and when I think it's enough to write like a direct access to the store.

And it would never violate the rule of the Redux, there are still in the rules.

How it works

Demo for the former

https://www.webpackbin.com/bins/-L1Fa9XXsqDXyZvAw1xy

Demo for the latter

https://www.webpackbin.com/bins/-L1FhpdeVNre0WTgO0x3

It's the core of the tricks. Enjoy them! :)

const TRIGGER_NAME = 'KERORIN_'

// Action Creator
export const dispactreducer = (reducerName, value) => {
  const ACTION_NAME = TRIGGER_NAME + reducerName + '_' + JSON.stringify(value)
  return ({ type: ACTION_NAME, reducerName, value })
}

// Reducer Enhancer
export const hookReducer = (reducer) => {
  const hooked = (state, action) => {
    if (action.type.startsWith(TRIGGER_NAME)) {
      if (reducer.name === action.reducerName) {
        const nextState = Object.assign({}, state, action.value)
        return nextState
      }
    }

    return reducer(state, action)
  }
  return hooked
}

Of course since it's not completed yet and I didn't use enough times, if it has some deficit, (I presume it has a lot) give me a comment.

If you can do, I'll fix them as soon as possible except for if I can afford to do :)