Closed juancampa closed 6 years ago
This was reported in #2842 (closed) but since there's a new API for forwarding refs I believe it should be reconsidered
Please create a minimal reproducible example in a github repo so it's easier to reproduce.
Sure, here it is:
https://github.com/juancampa/next-bug/blob/master/pages/index.js
Expecting this to be one of the cases for the new createRef
API
@juancampa You can use the forwardRef
api to implement it yourself.
pages/index.js
import React from 'react'
import dynamic from 'next/dynamic';
// Dynamically imported component
const Component = dynamic(import('../components/Component'));
const ForwardedRefComponent = React.forwardRef((props, ref) => (
<Component {...props} forwardedRef={ref} />
))
export default class Index extends React.Component {
constructor(props) {
super(props)
this.myRef = React.createRef();
}
componentDidMount() {
console.log('this.myRef', this.myRef)
}
render() {
return <ForwardedRefComponent ref={this.myRef}/>;
}
}
components/Component.js
export default ({ forwardedRef }) => (
<div ref={forwardedRef}>
Hi from Component
</div>
)
Please note: You can also omit the forwardRef
api and pass the ref as forwardedRef
in directly.
I don't think it makes sense to implement it in next now since:
Thanks @HaNdTriX!
@HaNdTriX what if we want to set ref on the Component
component itself?
Going to close this as the issue has been answered and @HaNdTriX's reasoning is correct.
is this going to be official workaround?
@HaNdTriX what if we want to set ref on the
Component
component itself?
Then, you can simply user other Component wrap all component using ref
. Then use dynamic on WrapperComponent. So the child component will use like usual
Solution
@juancampa You can use the
forwardRef
api to implement it yourself.
pages/index.js
import React from 'react' import dynamic from 'next/dynamic'; // Dynamically imported component const Component = dynamic(import('../components/Component')); const ForwardedRefComponent = React.forwardRef((props, ref) => ( <Component {...props} forwardedRef={ref} /> )) export default class Index extends React.Component { constructor(props) { super(props) this.myRef = React.createRef(); } componentDidMount() { console.log('this.myRef', this.myRef) } render() { return <ForwardedRefComponent ref={this.myRef}/>; } }
components/Component.js
export default ({ forwardedRef }) => ( <div ref={forwardedRef}> Hi from Component </div> )
Please note: You can also omit the
forwardRef
api and pass the ref asforwardedRef
in directly.Issues adding this functionality to next.js
I don't think it makes sense to implement it in next now since:
- react-loadable needs to implement it first
- React <16.3 needs to be deprecated first
- won't work with other rendering engines (e.g. preact)
how can i do with the custom Component not wroten by myself ? I cant set
export default ({ forwardedRef }) => (
<div **ref={forwardedRef}**>
Hi from Component
</div>
)
I'm trying to use forwardRef
on an external component but ref.current
is not the actual ref. Not sure if I'm missing something. Can anyone take a look, please?
Here it's my code: https://codesandbox.io/s/objective-benz-qh4ec?file=/pages/index.js:63-73
If you can't modify an imported component, then you'll have to hack into the DOM.
My workaround (or maybe it's just a forgotten canonical way?) is the following:
const Component = () => {
const ref = useRef();
const id = useState(shortid());
const DynamicComponent = eval('div') // Put whatever variable that contains your dynamic component
useEffect(() => {
ref.current = document.getElementById(id);
}, [DynamicComponent]);
return <DynamicComponent id={id} />
}
Be aware of that if you change your dynamic component due to some conditions, you need to add those conditions to useEffect so the ref is updated with your component.
@alvelig thanks for the response!
Sadly, I'm not sure if I follow this part:
eval('div') // Put whatever variable that contains your dynamic component
Can you explain it more, please?
Thanks 🙏
@matiastucci You have to wrap your component in a custom component and pass the ref through it.
See your modified example: https://codesandbox.io/s/relaxed-pine-b8f5z.
Note that you can use the custom prop way without using forwardRef
(example: https://codesandbox.io/s/busy-jennings-cxll6).
@matiastucci You have to wrap your component in a custom component and pass the ref through it.
See your modified example: https://codesandbox.io/s/relaxed-pine-b8f5z.
Note that you can use the custom prop way without using
forwardRef
(example: https://codesandbox.io/s/busy-jennings-cxll6).
In your example the ref is null, is this the proper result?
@giacomoalonzi If you check the console pane (not the terminal pane), you'll see that the ref is not null after the editor renders.
@fcFn Much appreciated, thanks!
Solution
@juancampa You can use the
forwardRef
api to implement it yourself.
pages/index.js
import React from 'react' import dynamic from 'next/dynamic'; // Dynamically imported component const Component = dynamic(import('../components/Component')); const ForwardedRefComponent = React.forwardRef((props, ref) => ( <Component {...props} forwardedRef={ref} /> )) export default class Index extends React.Component { constructor(props) { super(props) this.myRef = React.createRef(); } componentDidMount() { console.log('this.myRef', this.myRef) } render() { return <ForwardedRefComponent ref={this.myRef}/>; } }
components/Component.js
export default ({ forwardedRef }) => ( <div ref={forwardedRef}> Hi from Component </div> )
Please note: You can also omit the
forwardRef
api and pass the ref asforwardedRef
in directly.Issues adding this functionality to next.js
I don't think it makes sense to implement it in next now since:
- react-loadable needs to implement it first
- React <16.3 needs to be deprecated first
- won't work with other rendering engines (e.g. preact)
Thanks a bunch! Works with my next.js
+ typescript
project, you just need to add simple snippets below in Component.ts
:
interface ComponentProps {
forwardedRef: React.ForwardedRef<any>;
}
const Component: React.FC<ComponentProps> = ({ forwardedRef }) => {
...
}
This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.
Bug report
Describe the bug
When a component is wrapped in
next/dynamic
the passedref
should be a ref to the imported component, not an instance ofNoSsr
orLoadableComponent
To Reproduce
next/dynamic
render
passing aref
(use a function to received the ref)Result: the function is called with either a
NoSSR
component or aLoadableComponent
instead of an instance of the component imported in step 1Expected behavior
The function gets called with an instance of the dynamically loaded component
System information
6.1.1-canary.4
Additional context
Didn't try with
createRef
but it shouldn't make a difference