Продвинутые материалы

Здесь вы найдете материалы для пользователей glamorous более продвинутого уровня

innerRef

Как получить доступ к внутреннему свойству ref

Иногда бывает необходимо получить доступ к ref компонента, лежащего в основе вашего. Это возможно с помощью свойства innerRef.

Это свойство принимает функцию, которая будет вызвана с ref'ом внутреннего элемента в качестве аргумента.

Поле ввода в форме

Работа с текущим CSS

Часто вам придется внедрять glamorous на действующем проекте, который уже использует глобальный CSS. API glamorous позволяет сделать это без лишних усилий.

glamorous также работает с CSS модулями без дополнительных усилий с вашей стороны. Это Просто Работает™.

Вот пример с использованием Bootstrap:

// source https://v4-alpha.getbootstrap.com/components/alerts/

import React from 'react';
import { render } from 'react-dom';
import glamorous from 'glamorous';

const Alert = glamorous.div('alert', props => `alert-${props.type}`);

function App() {
  return (
    <glamorous.Div maxWidth={600} margin="70px auto" fontSize={24}>
      <Alert type="success">
        <strong>Успех!</strong> Тада! 🎉
      </Alert>
      <Alert type="info">
        <strong>Оповещение!</strong> Кое-какая информация ℹ️
      </Alert>
      <Alert type="warning">
        <strong>Внимание!</strong> Что-то случилось ⚠️
      </Alert>

      <Alert type="danger">
        <strong>Ох блин!</strong> Это совсем не хорошо 🚨
      </Alert>
    </glamorous.Div>
  );
}

render(<App />, document.getElementById('root'));

Попробуйте это в своем браузере здесь!

Если \<Alert success \/> вам больше по душе, чем \<Alert type="success" \/>, то этого просто добиться:

// source https://v4-alpha.getbootstrap.com/components/alerts/

import React from 'react';
import { render } from 'react-dom';
import glamorous from 'glamorous';

const Alert = glamorous.div('alert', props => {
  const types = ['success', 'info', 'warning', 'danger'];
  return types.reduce((all, t) => {
    if (props.hasOwnProperty(t)) {
      all = `${all} alert-${t}`;
    }
    return all;
  }, '');
});

function App() {
  return (
    <glamorous.Div maxWidth={600} margin="70px auto" fontSize={24}>
      <Alert success>
        <strong>Успех!</strong> Тада! 🎉
      </Alert>
      <Alert info>
        <strong>Оповещение!</strong> Кое-какая информация ℹ️
      </Alert>
      <Alert warning>
        <strong>Внимание!</strong> Что-то случилось ⚠️
      </Alert>
      <Alert danger>
        <strong>Ох блин!</strong> Это совсем не хорошо 🚨
      </Alert>
    </glamorous.Div>
  );
}

render(<App />, document.getElementById('root'));

Попробуйте это в своем браузере здесь!

Запомните

Главная цель CSS в JS - это стилизация компонентов и их повторное использование. Соответсвтенно, если вам нужно добавить стили всему приложению в целом (например, html/body или добавить reset стили), не стоит использовать для этого glamorous. Вместо этого, используйте обычный CSS или API glamor для внедрения глобальных стилей.

В дополнение, вместо того, чтобы использовать CSS для стилизации тега a с помощью глобального CSS, стоит создать компонент Link, присвоить ему все необходимые стили и использовать его.

Темы

glamorous полностью поддерживает создание тем с помощью специального <ThemeProvider> компонента.

Он предоставляет свойство theme всем компонентам glamorous, расположенным ниже в дереве.

import glamorous, {ThemeProvider} from 'glamorous'

// наш главный объект темы
const theme = {
  main: {color: 'red'}
}

// наш второстепенный объект темы
const secondaryTheme = {
  main: {color: 'blue'}
}

// <Title> компонент с применением темы
const Title = glamorous.h1({
  fontSize: '10px'
}, ({theme}) => ({
  color: theme.main.color
}))

// используйте <ThemeProvider>, чтобы передать тему ниже в структуре
<ThemeProvider theme={theme}>
  <Title>Привет!</Title>
</ThemeProvider>

// можно вкладывать темы друг в друга
// внутренняя тема будет объединена с внешней

<ThemeProvider theme={theme}>
  <div>
    <Title>Привет!</Title>
    <ThemeProvider theme={secondaryTheme}>
      {/* это будем синим */}
      <Title>Привет отсюда!</Title>
    </ThemeProvider>
  </div>
</ThemeProvider>

// чтобы сделать override темы, просто передайте свойств theme компоненту glamorous вручную
// компонент проигнорирует любую внешнюю тему и будет использовать ту, которая передана в props
<ThemeProvider theme={theme}>
  {/* это будет желтым */}
  <Title theme={{main: {color: 'yellow'}}}>Привет!</Title>
</ThemeProvider>

Попробуйте это в своем браузере здесь!

glamorous также предоставляет компонент высшего порядка withTheme, так что вы можете получить доступ к своей теме из любого компонента!

import glamorous, {ThemeProvider,  withTheme} from 'glamorous'

// наш главный объект темы
const theme = {
  main: {color: 'red'}
}

// <Title> компонент с применением темы
const Title = glamorous.h1({
  fontSize: '10px'
}, ({theme}) => ({
  color: theme.main.color
}))

// обычный компонент, принимающий свойство theme
const SubTitle = ({children, theme: {color}}) => (
  <h3 style={{color}}>{children}</h3>
)

// расширенный компонент со свойством theme
const ThemedSubTitle = withTheme(SubTitle)

<ThemeProvider theme={theme}>
  <Title>Привет!</Title>
  <ThemedSubTitle>от withTheme!</ThemedSubTitle>
</ThemeProvider>

Попробуйте это в своем браузере здесь!

Или если вы предпочитаете декораторы:

import React, {Component} from 'react'
import glamorous, {ThemeProvider,  withTheme} from 'glamorous'

// наш главный объект темы
const theme = {
  main: {color: 'red'}
}

// <Title> компонент с применением темы
const Title = glamorous.h1({
  fontSize: '10px'
}, ({theme}) => ({
  color: theme.main.color
}))

// расширенный компонент со свойством theme
@withTheme
class SubTitle extends Component {
  render() {
    const {children, theme: {main: {color}}} = this.props
    return <h3 style={{color}}>{children}</h3>
  }
}

<ThemeProvider theme={theme}>
  <Title>Привет!</Title>
  <SubTitle>от withTheme!</SubTitle>
</ThemeProvider>

withTheme ожидает, что ThemeProvider будет находиться выше в дереве рендера, и в development покажет предупреждение, если он не будет найден.

CodeSandbox

Context

context - это нестабильный API и его не рекомендуется использовать напрямую. Тем не менее, если вам по какой-то причине нужно его использовать, вот пример:

const dynamicStyles = (props, context) => ({
  color: context.isLoggedIn ? 'green' : 'red'
})
const MyDiv = glamorous.div(dynamicStyles)
MyDiv.contextTypes = {
  isLoggedIn: PropTypes.string,
}

class Parent extends React.Component {
  getChildContext() {
    return {
      isLoggedIn: true,
    }
  }
  render() {
    return <MyDiv />
  }
}

Parent.childContextTypes = {
  isLoggedIn: PropTypes.string,
}

<Parent />
// рендерит <div />
// с {color: 'green'}

Оптимизация размера

Этот перевод устарел.
Вы можете помочь улучшить его

Thanks for your interest in helping to update the website translations! The link below will take you to GitHub showing all the changes that happened between the last time /pages/advanced/content/ru/size.md was updated to when the /pages/advanced/content/size.md was most recently updated. Unfortunately this includes all file changes, not just changes in /pages/advanced/content/ru/size.md. So you'll have to click the "Files changed" tab, then search for /pages/advanced/content/ru/size.md in the changes. Then you can open the editor link to update the translation. Thanks again!!

Если в вашем проекте размер является важным ограничением, вам стоит рассмотреть возможность использования "tiny" версии glamorous. Это миниатюрная версия glamorous с рядом ограничений:

  1. Отсутствие встроенных фабрик компонентов (glamorous.article({/* styles */ })) Так что вам придется создавать свои. (glamorous('article')({/* styles */ }))
  2. Отсутствие встроенных компонентов glamorous (glamorous.Span)
  3. Отсутствие фильтрации props для динамических стилей. Вместо этого вам придется передавать их в специальном свойстве glam (смотрите пример ниже).
  4. Если вам нужен ThemeProvider или withTheme, придется импортировать их вручную. Они не являются частью экспорта glamorous/ tiny, в отличие от glamorous.

Вот пример того, что вы сможете с этим сделать.

import React from 'react'
import glamorous from 'glamorous/dist/glamorous.es.tiny'

const Comp = glamorous('div')({
  color: 'red'
}, (props) => ({
  fontSize: props.glam.big ? 20 : 12
}))
function Root() {
  return (
    <Comp
      glam={{ big: true }}
      thisWillBeForwardedAndReactWillWarn
    >
      ciao
    </Comp>
  )
}

export default Root

Улучшенный экспириенс

Рекомендуется использовать либо babel-plugin-module-resolver, либо resolve.alias конфигурацию с webpack, чтобы не приходилось импортировать с использованием полного пути.

У вас есть следующие варианты импорта:

  1. glamorous/dist/glamorous.es.tiny.js - используйте вместе с Webpack@>=2 или Rollup
  2. glamorous/dist/glamorous.cjs.tiny.js - используйте, если вы не преобразовываете ESModules
  3. glamorous/dist/glamorous.umd.tiny.js - ипользуйте, если хотите добавить через script тег (Также есть .min.js версия).

Текущий размер glamorous/dist/glamorous.umd.tiny.min.js: tiny size tiny gzip size

Важно

Так как glamorous зависит от glamor, вам следует учитывать полный размер файлов, которые вы добавите, если в вашем проекте еще нет glamor. Текущий размер glamor/umd/index.min.js: glamor size glamor gzip size

Рендеринг на сервере

Так как и glamor и react поддерживают рендеринг на сервере (SSR), то и glamorous его поддерживает! Я использую его на своем личном сайте, который генерируется во время билда на сервере. Узнайте больше о рендеринге react на сервере и glamor.

Для рендера на сервере используйте renderStatic из glamor, который принимает callback (функцию обратного вызова). При рендере вашего компонента в callback'е, все вызовы css() будут собраны, после чего будет возвращен сгенерированный html и css. Также будет возвращен массив id для регидрации стилей, необходимой для быстрого запуска.

Для регидрации вызовите rehydrate с массивом id, возвращенным из renderStatic, в качестве аргумента.

Пример -

import {renderStatic} from 'glamor/server'
import {rehydrate} from 'glamor'
import {render} from 'react-dom'
import ReactDOMServer from 'react-dom/server'

let {html, css, ids} = renderStatic(() => ReactDOMServer.renderToString(<App />))

return `
  <html>
    <head>
      <style>${css}</style>
    </head>
    <body>
      <div id="app">${html}</div>
      <script src="./bundle.js"></script>
      <script>
        rehydrate(${JSON.stringify(ids)});
        render(<App />, document.getElementById('app'));
      </script>
    </body>
  </html>
`

Использование с Next.js

Посмотрите на этот пример использования glamorous с Next.js

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

Из-за сложной природы es6 импортов, glamorous может добавлять дубликаты стилей на страницу.

Например:

import App from './App';

rehydrate(${JSON.stringify(ids)}) // id, полученные из renderStatic

Так как import транспилируется раньше остальных выражений, то rehydrate будет вызван после него, не зависимо в каком порядке вы указываете выражения. Это приводит к созданию дублированных стилей, потому что первым импортируется App и все стили добавляются прежде, чем будет выполнен rehydrate.

Чтобы избежать этой проблемы, используйте require() для выполнения выражений в определенном порядке.

rehydrate(${JSON.stringify(ids)});

const App = require('./App');

Если же вы используете какое-то другое решение, rehydrate должен всегда вызываться раньше любого другого кода, связанного со стилями.

Контрибьюторы:

kentcdodds's GitHub avatarpaulmolluzzo's GitHub avatarJReinhold's GitHub avatar