Как передать стили с помощью реквизитов со стилизованными компонентами, не создавая компонент внутри компонента

#javascript #reactjs #styled-components

Вопрос:

Я не могу найти другого способа придать своим реквизитам динамические стили, не создав styled-component внутри Text компонента. Для производительности я хотел бы создать компонент вне Text компонента.

Стилизованный Компонент

 import React, { ReactChildren } from 'react'
import styled from 'styled-components'


export const Text = ({ as = 'p', children, styles = {} }) => {
  const newStyles = Object.entries(styles).reduce((acc, [key, value]) => {
    return `${acc}${key}: ${value};`
  }, '')
  const Component = styled.p`
    ${newStyles}
    color: #000;
  `
  return <Component as={as}>{children}</Component>
}
 

Желаемое Использование

 <Text styles={{ height: "10px" }} />
 

Вывод HTML

 <p styles="height: 10px" />
 

введите описание изображения здесь

Комментарии:

1. Не могли бы вы просто сделать Object.entries немного за пределами стилизованного компонента и передать его?

2. Да, но проблема в том, чтобы иметь Component внутренний Text компонент. Поэтому, если бы я убрал и то, и другое, я не смог бы вернуть компонент из функции. Но, может быть, я могу и просто не могу этого видеть :p

Ответ №1:

Приведенный выше код сбивает с толку тем, что вы хотите применить стили к свойству DOM style , но вы также применяете их в качестве стилей CSS к имени класса. Нет необходимости создавать этот составной компонент, потому что styled-компоненты уже обрабатывают as , children , и style свойства без создания:

Редактирование стилизованных компонентов - Машинописный текст quot;Стилиquot;

Пример 1:

 import React from "react";
import styled, { Interpolation } from "styled-components";

export type TextProps = {
  as?: string | React.ComponentType<any>;
  children: React.ReactNode;
  styles?: Interpolation<React.CSSProperties>;
};

const Component = styled.p<TextProps>`
  ${({ styles }) => styles}
  color: #000;
`;

export const Text = ({
  as,
  children,
  styles
}: TextProps): React.ReactElement => (
  <Component styles={styles} as={as}>
    {children}
  </Component>
);

export default Text;
 

Пример 2:

 import styled from "styled-components";

const Text = styled.p`
  color: #000;
`;

export default Text;
 

Пример 3:

 import * as React from "react";
import styled from "styled-components";

export type TextComponentProps = {
  className?: string;
  children: React.ReactNode;
  styles?: React.CSSProperties;
};

const TextComponent = ({
  children,
  className,
  styles
}: TextComponentProps): React.ReactElement => (
  <p className={className} style={styles}>
    {children}
  </p>
);

const Text = styled(TextComponent)`
  color: #000;
`;

export default Text;
 

Использование:

 import * as React from "react";
import Box from "./Box";
import Text from "./Text";
import Text2 from "./Text2";
import Text3 from "./Text3";
import "./styles.css";

const App = (): React.ReactElement => (
  <div className="app">
    <h1>Example 1 - "styles" as CSS Styles</h1>
    <Box>
      <Text styles={{ height: "10px" }}>Hello</Text>
      <Text as="h1">Goodbye</Text>
    </Box>
    <hr />
    <h1>Example 2 - "style" as DOM styles</h1>
    <Box>
      <Text2 style={{ height: "10px" }}>Hello</Text2>
      <Text2 as="h1">Goodbye</Text2>
    </Box>
    <hr />
    <h1>Example 3 - "styles" as DOM styles</h1>
    <Box>
      <Text3 styles={{ height: "10px" }}>Hello</Text3>
      <Text3 as="h1">Goodbye</Text3>
    </Box>
  </div>
);

export default App;
 

Выход:
введите описание изображения здесь

На этой ноте звучит так, как будто вы, возможно, пытаетесь сделать то, что я сделал с компонентами в стиле composabled, хотя я бы не рекомендовал это, потому что это не работает с приложениями SSR.

Комментарии:

1. Спасибо, Мэтт… Интересно, что это неверный TS, о котором я, конечно, не упоминал в первоначальном вопросе.

2. Обновленный ответ, чтобы включить машинопись примеры TypeScript на codesandbox.

3. В соответствующем примечании, если вы хотите выполнить интерполяцию props в styles свойстве, которое добавляет стили CSS к имени класса, используйте вспомогательную функцию css (можно интерполировать объект или литерал шаблона).

4. Это чрезвычайно полезно. Спасибо!

Ответ №2:

Вы можете создать ref компонент в стиле, чтобы задать стиль в эффекте, подобном этому:

 const Component = styled.p`
  background-color: red;
`;

const Text = ({ as = 'p', children, styles = {} }) => {
  const newStyles = Object.entries(styles).reduce((acc, [key, value]) => {
    return `${acc}${key}: ${value};`
  }, '')
  
  const ref = React.createRef();

  React.useEffect(() => {
    ref.current.style = newStyles;
  }, []);
  
  return <Component ref={ref} as={as}>{children}</Component>
}

ReactDOM.render(<Text styles={{ height: "10px" }}>This paragraph is 10px high</Text>, document.getElementById('root')); 
 <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script></script>
<script src="https://unpkg.com/react-is@17/umd/react-is.production.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>

<div id="root"></div> 

Комментарии:

1. Очень интересное решение. Мне кажется странным, что для этого мне нужно было бы использовать визуализированный DOM, а не использовать react. Я подумаю об этом, спасибо