alveron icon indicating copy to clipboard operation
alveron copied to clipboard

Middleware Proposal

Open robinweser opened this issue 6 years ago • 9 comments

Middleware

This PR adds a minimal API for adding middleware. Middleware are functions that receive the new state and return a (modified) new state.

import { createStore } from 'alveron'

const model = 0
const actions = {
  increment: state => state + 1,
  decrement: state => state - 1
}

const { Provider, Consumer } = createStore({ 
  model, 
  actions
})

const logger = (state, context) => {
  console.log(state)
  console.log(context)
  return state
}

const Usage = () => (
  <Provider middleware={[logger]}>
    <Consumer>{({ state, actions }) => (
      <div>
        Count {state}
        <button onClick={actions.increment}>+</button>
        <button onClick={actions.decrement}>-</button>   
    )}</Consumer>
  </Provider>
)

Doing the following:

  1. Click on +
  2. Click on +
  3. Click on -

will trigger the listeners, which logs the current state:

1
{ action: 'increment', payload: [], previousState: 0 },
2
{ action: 'increment', payload: [], previousState: 1 },
1
{ action: 'decrement', payload: [], previousState: 2 },

robinweser avatar Jul 31 '18 17:07 robinweser

@farskid What do you think on this one? Might be a better idea to add it to the createStore method as well, having a single source of truth that can be customized etc.

robinweser avatar Jul 31 '18 17:07 robinweser

I like the idea of having middlewares. is there a specific reason behind the name listeners? cause it seems to me, they are middlewares and not subscribe funcs, right?

farskid avatar Jul 31 '18 17:07 farskid

Actually they’re more like subscribe functions as they do not alter the state (thats what actions, effects are for).

They should rather be used for logging, caching etc.

Or is there a good reason why they should be able to alter state?

robinweser avatar Jul 31 '18 18:07 robinweser

OK, I've got a proposal:

What if we have the middlewares in a way that matches the middleware interface of Redux? a function that accepts store => next => action.

There a couple of pros on this approach:

  1. It's a familiar convention considering Express, Redux, ...
  2. It eases the migration from Redux to WoodWorm (if that's what we aim for)
  3. All middlewares from Redux can be ported to WoodWorm with no effort.
  4. It solves the issue of async actions (effects) by using old solutions in redux such as Thunk and Saga.

What do you think?

farskid avatar Aug 01 '18 07:08 farskid

That's not possible as we need to have synchronous middleware as it's executed within React's async setState already... We could have middleware with the following API: (currentState) => nextState but that's all here.

All other options would drastically change the current behaviour which is too verbose for me as that's the whole point with this micro package.

robinweser avatar Aug 01 '18 08:08 robinweser

That is true! (currentState) => [compose_all_middlewares_resutls_here] => nextState is a fine API. we can do the setState as the final step on nextState in order not to get into the pitfall on async state updates.

farskid avatar Aug 06 '18 10:08 farskid

@farskid I updated the PR, would love to hear your thoughts :)

robinweser avatar Aug 15 '18 12:08 robinweser

This sounds like a promising start.

question: Does middleware get called on effects too? Am I missing something here?

farskid avatar Aug 17 '18 10:08 farskid

Effects now actually dont mutate state directly, but call actions instead which then triggers middleware again ;)

robinweser avatar Aug 17 '18 11:08 robinweser