Recompose: Add documentation of refs and function components

Created on 22 Oct 2015  路  23Comments  路  Source: acdlite/recompose

Because withProps using stateless components, connect attaching ref to child component, and react doesn't allow attach ref to stateless components.

docs enhancement

Most helpful comment

It depends on case, in a lot of cases where I need refs I don't use recompose at all and use just React classes, as refs are mostly used at low level.

Sometimes I use them like,

compose(
  withHandlers(() => {
     let ref_;
     return {
        registerChild: () => (ref) => {
           ref_ = ref;
        },
        otherHandler: () => () => {
          // I can use ref here.
        }
     };
  })
)

Sometimes as like as above comment,
and sometimes for React Sortable for example I used it like

compose(
  bc => SortableContainer(bc, { withRef: true }), // eslint-disable-line
  toClass
);

so toClass will allow to get Dom element instance of any component

All 23 comments

This is a problem with any function component, not just the ones provided by Recompose. One fix is add pure() in between connect() and withProps().

We should probably also document which helpers return a class component and which ones return a stateless component.

I found another solution: fresh version of redux doesn't use refs by default.

Should I close the issue?

I'll keep it open as a reminder to add documentation about refs.

I put together a jsfiddle that tests the output of the various HOCs here: https://jsfiddle.net/emilong/rcdovojw/3/

If this makes sense, I can take the output and add it to the documentation. One major assumption that would be good to get confirmation on is that Recompose.isClassComponent returning false means stateless component. Not sure if I'm getting the terminology and/or concepts right there.

Having a nice way to add refs with recompose becomes even more important as React deprecates returning a component from render. Normally our tests use this component to find the DOM objects, but in the future we are supposed to use refs.

So we need a great way to get a ref to the hoc via recompose so we don't have to resort to manually created classes. I was thinking maybe a new helper like withRef ? Something that will ensure that regardless of what you have composed together with recompose that you will get a valid ref.

@jeffbski does toClass() work for your case?

Possibly but I would like to see some examples of how that is done.

Looking at the API reference for toClass() doesn't give me any ideas about how I can create a ref.

Could someone add an example or point me to a test?

Normally our tests use this component to find the DOM objects, but in the future we are supposed to use refs.

Why not use Enzyme? Refs are gross.

See this issue for an explanation of the current problems with HOCs and refs https://github.com/facebook/react/issues/6974

I haven't seen a need for Enzyme yet, my tests are really simple without it, though now this may be a reason to use it.

I don't like refs either, but they are the recommended approach for getting the root component back in React 16+ https://github.com/facebook/react/issues/6397 since they are deprecating the return value of render().

Frankly if it were up to me, I'd rather have a way to optionally provide a callback to render and just get async notified with the component rather than using a ref.

Has anyone figured out how to actually use toClass, especially with refs? Documentation seems to be missing here.

What is your use case for refs with toClass?
I'm asking because you need toClass only if your component is a function, so why do you need an instance to it? If you need an instance of Dom element just write ref={registerRef} at top level Dom element of component.

If have contributed a ref function, but this.refs is always empty when I attempt to make use of this ref.

For example:

const enhance = compose(
  lifecycle({
    componentDidUpdate: function(prevProps) {
      console.log(this._myRef) // undefined
    }
  })
)

class Foo extends React.Component {
  render() {
    return <div ref={ component => this._myRef = component } />
  }
}

export default enhance(Foo)

Why not to register refs explicitly using function syntax in your case? ie

const MyComp = ({ registerChild }) => <div ref={registerChild}>Blabla</div>

Now you can get ref of MyComp using <MyComp registerChild={registerChild} />

Your case with lifecycle will not work at all, all is enhancer not the same component.
Your this points to lifecycle component instance not on yours. Please read about Higher-Order Components

so how can I get access to an element in this case? stateHandler as my ref function? or something else?

I don't know your case, I wrote before one of example how. There are many ways to do this.

i don't know what registerChild is in your example

What it can be based on React documentation?

It depends on case, in a lot of cases where I need refs I don't use recompose at all and use just React classes, as refs are mostly used at low level.

Sometimes I use them like,

compose(
  withHandlers(() => {
     let ref_;
     return {
        registerChild: () => (ref) => {
           ref_ = ref;
        },
        otherHandler: () => () => {
          // I can use ref here.
        }
     };
  })
)

Sometimes as like as above comment,
and sometimes for React Sortable for example I used it like

compose(
  bc => SortableContainer(bc, { withRef: true }), // eslint-disable-line
  toClass
);

so toClass will allow to get Dom element instance of any component

Thanks for the clarification. I'm thinking that recompose is not an ideal choice for this particular situation, as you mentioned earlier.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

franklinkim picture franklinkim  路  3Comments

jethrolarson picture jethrolarson  路  4Comments

isubasti picture isubasti  路  3Comments

rockchalkwushock picture rockchalkwushock  路  3Comments

Secretmapper picture Secretmapper  路  3Comments