I used to have refs in my component when rendering, and it worked:
// props.children is ReactElement<HTMLDivElement>[]
const [childRefs] = useState<RefObject<any>[]>(props.children.map(() => createRef()));
// working code, all the variables (props, childRefs etc) are defined earlier in scope
return <div {...props}>
{
props.children.map((c, i) => <div key={i} ref={childRefs[i]}>{c}</div >)
}
</div>
Basically I'm using the refs to imperatively directly set some transforms to style as mouse moves on JS mousemove
event.
However, I now need to inject some CSS class into the passed component automatically. I've created a component (named Layer
) that takes the child element, clones it, sets the CSS class, and returns it:
function Layer(props:LayerProps){
const elem = cloneElement(props.children, {...props.children.props,
className: styles['layer']
});
return elem;
}
I've updated the main component like this too:
return <div {...props}>
{
props.children.map((c, i) => <Layer key={i} ref={childRefs[i]}>{c}</Layer>)
}
</div>
However now my ref
s aren't passed now, understandibly, as the Layer
functional component can't have a ref
(as it's a function). When I try to set the ref
to Layer
it can't, and have this error (understandably):
(property) ref: React.RefObject<any>
Type '{ children: ReactElement<HTMLDivElement, string | JSXElementConstructor<any>>; key: number; ref: RefObject<any>; }' is not assignable to type 'IntrinsicAttributes & LayerProps'.
Property 'ref' does not exist on type 'IntrinsicAttributes & LayerProps'.ts(2322)
If I try to forward the ref
using forwardRef
it doesn't have anything to set that ref to as I'm just modifying the passed child element and returning it, not returning a new element like <div>...</div>
that I could forward ref to like <div ref={forwardedRef}>...</div>
.
How can I modify the CSS class and keep a ref
to the object? I know how to do each one (if I just need to add class I cloneElement
, if I just need to ref it I use forwardRef
and pass it to the child component in JSX) yet I couldn't figure out being able to do both at the same time.
How can I do it?
Okay, after a bit digging and experimenting I've realized I can give ref
"prop" (which isn't technically a real prop, but anyway) in cloneElement
just like any prop.
I've ended up forwarding ref to the functional component, and provided ref
as a prop to the newly cloned element, and it worked.
Yet, the TypeScript definitions are incorrectly flagging ref
property as non-existent while it works perfectly. I needed it to cast the props to any
to silence the linter error though:
const Layer = forwardRef((props:LayerProps, ref:any) => {
const elem = cloneElement(props.children, {...props.children.props,
className: `${props.children.props.className ?? ''} ${styles['layer']}`,
ref: ref
} as any); // as any fixes ref complaining
return elem;
});
And in many component:
return <div {...props}>
{
props.children.map((c, i) => <Layer key={i} ref={childRefs[i]}>{c}</Layer>)
}
</div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.