1

I want to use withPropsOnChange to create a new debounced function based on the props that were passed in. If the props are changed, it should create a new function. withPropsOnChange seems perfect for this, except that I need access to this.state inside of the createProps callback, which recompose doesn't provide.

What are the alternatives? i.e. how can I create a property (React or vanilla) that's contingent/depends-on on some other properties and is automatically updated when those props are updated?


Here's the gist of what I've got now:

class MyClass extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            isOpen: false,
            isLoading: 0,
            isWaiting: false,
            searchQuery: '',
            options: [],
            value: undefined, 
            highlightedValue: undefined,
            scrollPos: 0,
        };
        if(props.options) {
            this.loadOptions = Lo.debounce(searchQuery => {
                this.setState(state => ({
                    isLoading: state.isLoading + 1,
                }));
                props.options(searchQuery).then(result => {
                    this.setState(state => ({
                        isLoading: state.isLoading - 1,
                        options: result.options,
                    }));
                });
            }, props.delay);
        }
    }
}

As you can see, I'm defining a property called this.loadOptions which is just a debounced copy of props.options with some state handling.

This works adequately for now, but if the upstream modifies props.options or props.delay, then this.loadOptions won't be updated because I'm only doing this in the constructor.

Now I could do all this again in componentWillUpdate, but really I only want to do it if either props.options or props.delay are updated, because those are its only two dependencies.

I'm just looking for a cleaner design pattern to deal with this sort of thing. It's basically just "computed properties" now that I think about it (but I can't "recompute" it as needed -- I need the same instance back each time unless those properties are modified).

jonahe
  • 4,820
  • 1
  • 15
  • 19
mpen
  • 272,448
  • 266
  • 850
  • 1,236

1 Answers1

1

So, as I understand it, you have some state that is currently internal to the component. And you would like to use that state inside of the createProps callback.

Would it be possible to use recompose to extract that internal state (and its logic), with withState?

Then, if you "start" the composing of recompose functions with the withState, state should be available "further down" as props. (Or at least that's my understanding.)

const enhance = compose(
  // handle previously internal state
  withState('importantState', 'changeImportantState', 0),
  withHandlers({
    logicForChangingTheImportantState:
        props => () => props.changeImportantState(old =>  ({...old, moreImportant: 'xyz'}))
  }),
    // do your logic here
  withPropsOnChange(
    [], // ?? shouldMapOrKeys
    (props) => {
        return {
        thisPreviouslyDependedOnInternalState: props.importantState
      }
    }    
  ) 
);
jonahe
  • 4,820
  • 1
  • 15
  • 19
  • I might be able to move all the state into props via `withState`, but then I have to move all my handlers over too (like you've shown), which is a bit more refactoring than I wanted to do. – mpen Aug 25 '17 at 01:21
  • 1
    Ok yeah, that's understandable. It's considerably easier to "externalize" state like that when you write the code for the first time. I once tried getting into the habit of only writing simple/dumb functional components and handling all the state with `withState` (and redux). But even then, when I didn't need to refactor anything, it was kind of hard and un-intuitive to code like that. So my experiment didn't last for long. /end of pointless storytime. – jonahe Aug 25 '17 at 01:32
  • I did basically the same thing. Tried putting all my state in my components. Then I discovered recompose, tried making everything 'dumb' for awhile, and then I decided this component was too complicated to make dumb, so I started writing it the old fashioned way, and then discovered one or two things would be much easier with recompose, so I brought a couple of those HOCs back in... and now I've got this mess. – mpen Aug 25 '17 at 01:39