generalui / hooks-for-redux

modular redux - in half the code
MIT License
96 stars 13 forks source link

Add support for accessing the raw action and raw action creator #5

Open qwerty0981 opened 4 years ago

qwerty0981 commented 4 years ago

Add API for accessing raw action and raw action creator

This PR adds support for accessing the generated action type and having a minimal API for accessing the internal raw action creator. Having access to these pieces of information would cover the only use-case that I have found where the pre-loaded action creators created by hooks-for-redux were not sufficient, using redux middleware like redux-saga or redux-rx.

Both of the middleware mentioned above need to have access to the raw action type to be used effectively and redux-rx specifically needs access to the basic action creator for use in bindActionCreators().

Example

// counter.js
import { createReduxModule } from 'hooks-for-redux';

// Create the module just like normal
export const [ useCounter, { increment, decrement, incrementBy }] = createReduxModule("counter", 0, {
    increment: (state) => state + 1,
    decrement: state => state - 1,
    incrementBy: (state, delta) => state + delta
})

// 'increment' and 'decrement' can now be used the same as before
increment() // state: 0 -> 1
increment() // state: 1 -> 2
decrement() // state: 2 -> 1

// Now the action creator's internal type can be accessed
console.log(increment.type)  // "counter-increment"
console.log(decrement.type)  // "counter-decrement"

// And you can get access to the raw action creator for integration in other libraries
console.log(increment.toAction())    // { type: "counter-increment" }
console.log(decrement.toAction())    // { type: "counter-decrement" }
console.log(incrementBy.toAction(2)) // { type: "counter-incrementBy", payload: 2 }

Example usage in redux-saga (this integration was impossible before)

// sagaCounter.js
// Import action from the example above
import { incrementBy } from './counter'
import { call, put, takeLatest } from 'redux-saga/effects'

// import fake API
import * as API from './api'

// Saga action creator
const counterActionType = "REMOTE_COUNTER_ACTION"
export const callRemoteCounter = amountToChange => { return { type: counterActionType, payload: amountToChange }}

// Saga definition
function* counterSaga(action) {
    try {
        const canIncreaseCounter = yield call(API.callRemoteCounterMethod, action.payload);

        if (canIncreaseCounter) {
            yield put(incrementBy.toAction(action.payload));
        } else {
            // do nothing (there would be some failure logic like setting a not authorized error
        }
    } catch (e) {
       // do nothing (there would be some failure logic like setting a remote call failed error
   }
}

// Create Saga to be included in store creation
function* counterSagas() {
  yield takeLatest(counterActionType, counterSaga);
}
shanebdavis commented 3 years ago

Thanks for this submission!

I wish Github notified me of it ;). I'm just noticing it now. I'll dive in deeper in a bit and see if it fits.

shanebdavis commented 3 years ago

Quick glance at the changes... looks pretty good.