Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 16.3+ forwardRef component #48

Closed
Cap32 opened this issue May 11, 2018 · 7 comments
Closed

React 16.3+ forwardRef component #48

Cap32 opened this issue May 11, 2018 · 7 comments

Comments

@Cap32
Copy link

Cap32 commented May 11, 2018

React 16.3+ forwardRef() will return a new component (type is object) that contains a render function and a $$typeof Symbol, and these should not be copied, otherwise may cause some bug

Example to reproduce

import React, { Component, createRef, forwardRef } from 'react';
import hoistStatics from 'hoist-non-react-statics';

function hoist(WrappedComponent) {
	return function createHoistedComponent(TargetComponent) {
		const HoistedComponent = forwardRef((props, ref) => (
			<TargetComponent {...props} forwardedRef={ref} />
		));

		if (WrappedComponent) {
			HoistedComponent.displayName = `hoisted(${WrappedComponent.displayName})`;
			hoistStatics(HoistedComponent, WrappedComponent /* , { render: true } */);
		}

		return HoistedComponent;
	};
}

function extraPropsHoc(extra) {
	return (WrappedComponent) => {
		@hoist(WrappedComponent)
		class Bar extends Component {
			render() {
				const { forwardedRef, ...props } = this.props;
				return <WrappedComponent {...props} {...extra} ref={forwardedRef} />;
			}
		}
		return Bar;
	};
}

@extraPropsHoc({ foo: 'foo' })
@extraPropsHoc({ bar: 'bar' })
class Foo extends Component {
	static displayName = 'Foo';

	log() {
		console.log('this.props', this.props);
	}

	render() {
		return <h1>Hello</h1>;
	}
}

export default class App extends Component {
	ref = createRef();

	componentDidMount() {
		this.ref.current.log();
	}

	render() {
		return <Foo ref={this.ref} />;
	}
}

Result

this.props {bar: "bar"}

Expect

this.props {foo: "foo", bar: "bar"}

If I uncomment hoistStatics(HoistedComponent, WrappedComponent /* , { render: true } */), it will work as expected.

Env

  • react@16.3.2
  • hoist-non-react-statics@2.5.0
@mridgway
Copy link
Owner

The annotations are a little confusing here, but I think I understand the use case. It should be as easy as adding render to the REACT_STATICS list right?

@Cap32
Copy link
Author

Cap32 commented May 21, 2018

This is okay, but not perfect. Because it will not hoist render static in traditional (which type is function) components, and it will not hoist propTypes static in forwardRef (which type is object) components (please note propTypes is non-react specific static in forwardRef component).

IMHO adding component type conditions to detect non-react specific statics would be better.

Thanks for replying. 😀

@mridgway
Copy link
Owner

mridgway commented May 22, 2018

Agreed on the component type specific logic. Here is what I'm thinking:

  • Derive the list of statics to ignore from both the targetComponent and the sourceComponent
  • Use ReactIs to do type checks for the components
    • For ForwardRef use a special list of statics: $$typeof and render
    • Default to the current list of React Statics

I am working through some issues in ReactIs to do type checking correctly right now, but I should be able to get a PR open for this this week.

@lifeiscontent
Copy link

@mridgway any updates here?

@mridgway
Copy link
Owner

mridgway commented Jul 2, 2018

I will work on getting this in soon. It looks like React maintainers will not be adding a react-is for non-elements, so I will need to add a dependency on react. I don't think this should be an issue for anyone.

@mridgway
Copy link
Owner

mridgway commented Jul 5, 2018

I opened #55 and published 3.0.0-rc.0 so that you can start testing the changes.

@mridgway
Copy link
Owner

v3.0.0 is now published as latest.

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

No branches or pull requests

3 participants