Nick Brady
Nick Brady

Reputation: 6572

Defining function for withHandler in Recompose for React

All of the examples I look at, the function actually called in withHandlers seems to call a function from props, but I have no idea how that function is defined. Here is a small example from docs for humans.

compose(
  withState('count', 'setCount', 0),
  withHandlers({
    incrementCount: props => event => {
      event.preventDefault()
      props.setCount(props.count + 1)
    }
  })
)(ComponentToEnhance)

My understanding is this will create a HOC with "state" to track count. I would be able to increment the count via an action used the defined handler (e.g. onClick={incrementCount}).

My question is then, where is setCount actually defined.. I'm imaging something like

function setCount(i) {
    return i+1;
}

Since it is called from props, do you have to pass it in as props when your using the component? I'm confused why withState would need to know the state updater name, or how it is even related if that is the case.

Does it just define a function automatically for you that will replace the state param with whatever argument you pass it (facepalm if so..)

Upvotes: 5

Views: 5149

Answers (2)

Perspective
Perspective

Reputation: 632

withHandlers takes a curried / higher order function in order to set the props from other HOC (high order component)'s such as withSate or form it's usage.

Enhanced component example:

import { compose } from 'recompose';
import React from 'react';

const enhance = compose(
  withState('count', 'setCount', 0),
  withHandlers({
    incrementCount: props => event => {
      // props would contain copy prop. 
      props.setCount(props.count + 1)
    },
    otherExample: () => event => {
      // If you didn't need props in your handler
    },
    otherIncrementCountExample: ({ count, setCount }) => () => {
      // you can exclude event also
      setCount(count + 1);
    }
  });

export default IncButton = ({ count, incrementCount, copy }) => (
  <div>
   <button onClick={incrementCount}> {copy} </button>
  </div>
);

Usage:

import React from 'react';
import IncButton from './IncButton';
export default App = () => (
  <div>
    <IncButton copy="Increment Me"/>
  </div>
);

Upvotes: 3

Nick Brady
Nick Brady

Reputation: 6572

Found out the answer, my example here is simpler than my component, but I'll do my best to translate my findings... though this isn't tested below.

compose(
  withState('count', 'setCount', 0),
  withHandlers({
    incrementCount: props => event => {
      props.setCount(props.count + 1)
    }
  })

(facepalm), it is as I suspected in my question. withHandlers just automatically defines a function for you that will replace the state param with whatever argument you pass it. It is not a smart function, though useful. It will take whatever argument you give it, and update your HOC's state with that argument. You'd use it like this...

function ComponentToEnhance({someProp="default str", ...props}) {
  return (
    <div>
      <h1>{props.count}</h1>
      <button onClick={props.setCount}/>
    </div>
  );
}

someProp is just there to show use of spread operator if you want some props that have a default or get passed in you want to call out specifically...cheers

Upvotes: 0

Related Questions