简体   繁体   中英

Emotion styled component and React.forwardRef not working together

I'm trying to write two React styled components (with Emotion 10), specifying some custom render logic into one of them, and preserving the ability to retrieve their "refs".

This is my code:

const Foo = styled(props => <div {...props} />)`
  color: red;
`;

// Here I **want** to use the component selector
// https://emotion.sh/docs/styled#targeting-another-emotion-component
const Bar = styled.div`
  ${Foo} {
    background-color: yellow;
  }
`;

const App = () => {
  const ref = React.useRef();
  return <Bar><Foo ref={ref}>foo</Foo></Bar>;
};

ReactDOM.render(<App />, document.body);

The issue with this code is that React throws this warning:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

As we know, Emotion styled components make use of React.forwardRef to enable developers to use the ref property on them. But it seems to not work as soon you switch to a custom render method.

Then, if I (awkwardly [1] ) convert it to use React.forwardRef what I get is:

const Foo = React.forwardRef((props, ref) => {
  const Component = styled(props => <div {...props} />)`
    color: red;
  `;
  return <Component {...props} ref={ref} />;
});

const Bar = styled.div`
  ${Foo} {
    background-color: yellow;
  }
`;

const App = () => {
  const ref = React.useRef();
  return <Bar><Foo ref={ref}>foo</Foo></Bar>;
};

ReactDOM.render(<App />, document.body);

But then, I get a different error:

TypeError: Cannot convert a Symbol value to a string

Which is happening where I try to use ${Foo} . Probably because Emotion expects a styled component but I'm now providing a forwardRef component.

Here's a CodeSandbox to make it easier to play with my code:
https://codesandbox.io/s/7ylnlovlz6

So, what's the proper way to achieve what I'm trying to get?

[1]: I know defining a component inside a render will make the component re-render on each render, but it's irrelevant in this context.

Now you don't need to do anything. Emotion handles ref correctly. This code will work.

const Foo = styled(props => <div {...props} />)`
  color: red;
`;

const Bar = styled.div`
  ${Foo} {
    background-color: yellow;
  }
`;

const App = () => {
  const ref = React.useRef();
  return <Bar><Foo ref={ref}>foo</Foo></Bar>;
};

ReactDOM.render(<App />, document.body);

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM