Skip to content
This repository has been archived by the owner on Sep 10, 2022. It is now read-only.

withStateHandlers (new withState) #421

Merged
merged 2 commits into from
Jul 6, 2017
Merged

withStateHandlers (new withState) #421

merged 2 commits into from
Jul 6, 2017

Conversation

istarkov
Copy link
Contributor

@istarkov istarkov commented Jul 3, 2017

This closes #308 and I think #357
withState alternative, which can be used without a pain with flowtype

Example:

  const Counter = withStateHandlers(
    ({ initialCounter = 0 }) => ({
      counter: initialCounter,
      value: ''
    }),
    {
      incrementOn: ({ counter }) => (value) => ({
        // { counter } is a state prop
        counter: counter + value,
      }),
      decrementOn: ({ counter }) => (value) => ({
        counter: counter - value,
      }),
      resetCounter: (_, { initialCounter = 0 }) => () => ({
        // initialCounter is a parent props
        counter: initialCounter,
      }),
     onChange: () => ({ target: { value }}) => ({
       value // merges state as like as React
     }),
     onBlur: ({ value, counter }, { onChanged }) => () => {
        onChanged({ value, counter });
        return undefined; // no rerender
     }
    }
  )(
    ({ counter, incrementOn, decrementOn, resetCounter, value, onChange }) =>
      <div>
        <Button onClick={() => incrementOn(2)}>Inc</Button>
        <Button onClick={() => decrementOn(3)}>Dec</Button>
        <Button onClick={resetCounter}>Dec</Button>
        <Input value={value} onChange={onChange} onBlur={onBlur} />
      </div>
  )

This is somehow similar to reason-react updaters, but without Silent updates, and
state updaters are explicitly defined inside withStateHandlers and passed via props to Base Component.

See tests and docs for usage.

flowtype definition:

type Void_<A, B, C, D, R, Fn: (A, B, C, D) => R> = (A, B, C, D) => void;

declare module 'recompose' {
   ...
  declare type Void<T> = Void_<*, *, *, *, *, T>;

  declare type ExtractStateHandlersCodomain = <State, Enhanced, V>(
    v: (state: State, props: Enhanced) => V
  ) => Void<V>;

  declare function withStateHandlers<
    State,
    Enhanced,
    StateHandlers: {
      [key: string]: (
        state: State,
        props: Enhanced
      ) => (...payload: any[]) => $Shape<State>,
    }
  >(
    initialState: State | ((props: Enhanced) => State),
    stateUpdaters: StateHandlers
  ): HOC<
    {
      ...$Exact<Enhanced>,
      ...State,
      ...$ObjMap<StateHandlers, ExtractHandlersCodomain>,
    },
    Enhanced
  >;
...
}

@wuct @timkindberg @TrySound and others your thoughts?

PS: see also following comment gif

@istarkov istarkov self-assigned this Jul 3, 2017
@istarkov istarkov changed the title With stateHandlers (new withState) withStateHandlers (new withState) Jul 3, 2017
@istarkov
Copy link
Contributor Author

istarkov commented Jul 3, 2017

type inference example

type-inference

Repository owner deleted a comment from codecov-io Jul 3, 2017
@timkindberg
Copy link
Contributor

Pretty cool! I really like how it's developed with typings in mind. (Even though I don't use typings, yet)

I did notice you still have an anonymous function within the JSX Button onClick prop. You think there is a way to eliminate that and have only function references? Might not be possible without declaring each function ahead of time.

@istarkov
Copy link
Contributor Author

istarkov commented Jul 6, 2017

@timkindberg There is no need in anonimous functions here, you could always use state handler like as in first PR comment to extract event data etc

     onChange: () => ({ target: { value }}) => ({
       value // merges state as like as React
     }),

....
<Input value={value} onChange={onChange} onBlur={onBlur} />

I'm now in process of finishing flow lib definitions for recompose and IMO it will be a good thing.
For now from what I see, it will be possible just to declare enhanced component type, and all other types inside enhancers and base component will be inferred automatically.

So example at the picture above is somehow outdated as it declares base component type too.

@istarkov istarkov merged commit dcaee67 into master Jul 6, 2017
@istarkov istarkov deleted the withStateHandlers branch July 6, 2017 19:30
@benxgao
Copy link

benxgao commented Jul 6, 2017

Thanks @istarkov , may I wonder when potentially the feature would be released, the team here cannot wait to adopt it? :D

@istarkov
Copy link
Contributor Author

istarkov commented Jul 6, 2017

In a few days Ill add a good support of flow lib definitions with examples etc, and release this as an major update, I think at next wednesday or monday

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

withState alternatives
3 participants