Material-ui: [withStyles] Добавить возможность получать свойства компонента из объекта стиля.

Созданный на 2 авг. 2017  ·  39Комментарии  ·  Источник: mui-org/material-ui

Описание

При использовании createStyleSheet нет способа (по крайней мере, о котором я знаю) получить доступ к реквизитам компонента. Я думаю, что это важно, поскольку иногда требуется передать размеры, изображения URL-адресов и другие стили в качестве свойств компонента.

Сегодня единственное решение - разделить эти вещи на встроенные стили, но, насколько я знаю, material-ui v1 использует jss и react-jss , и эти два уже дают вам возможность доступа к реквизитам через функции, которые получают реквизиты, а затем возвращают желаемый стиль, например:

const styles = {
  button: {
    background: props => props.color
  },
  root: {
    backgroundImage: props => `url(${props.backgroundImage})`
  }
}

// Reference: https://github.com/cssinjs/react-jss#example

Что вы думаете о реализации чего-то подобного и в material-ui?

enhancement important

Самый полезный комментарий

Я добавляю эту проблему в этап v1.x. Многие люди этого просят. Мы скоро к этому дойдем.

capture d ecran 2018-07-29 a 13 12 03

Все 39 Комментарий

react-jss реализует эту функцию. Вы всегда можете использовать его поверх нашего решения для укладки. Настоящая мотивация для реализации этой функции здесь должна заключаться в более простой / лучшей внутренней реализации компонентов.

response-jss injectStyles () тоже делает это, но похоже, что было бы лучше добавить реквизиты к StyleRuleCallback .

const styles = (props, theme) => ({})
Таким образом, вы не ограничены только значениями, зависящими от реквизита.

Обратная связь color вместо предопределенного. Влияние размера CSS неясно, но это сделало бы переопределение цвета компонента еще проще. Это то, что нужно исследовать. Затем, когда поддержка браузерами css-переменных станет достаточно высокой (через 2 года?), Мы сможем на нее положиться.

@oliviertassinari, разве в некоторых случаях размер CSS не уменьшится?
Как я понял, в настоящее время мы определяем все классы для ...Primary и ...Accent - не будет ли это изменение означать, что нам нужно будет поддерживать классы только для ...Colorized ? Или вас беспокоит сгенерированный css?

В любом случае, я думаю, что это значительно улучшит dx, поскольку мы должны в основном переопределить сложные классы, такие как https://github.com/callemall/material-ui/blob/v1-beta/src/Button/Button.js#L11, когда мы хотите использовать цвета, отличные от палитры.

не уменьшится ли размер css в некоторых случаях?

@sakulstra Трудно сказать. Это будет зависеть от реализации. Может быть :).

С точки зрения типизации TypeScript было бы неплохо, если бы _both_ props и theme могли быть доступны таким образом в спецификации стилей:

const styles = {
  button: {
    background: ({ theme }) => theme.palette.primary[200]
  },
  root: {
    backgroundImage: ({ props }) => `url(${props.backgroundImage})`
  }
};

Причина в том, что TypeScript часто не может определить правильный тип для withStyles когда ему передается объект функции, поэтому вам нужно предоставить дополнительные аннотации типов, чтобы заставить его работать, например

withStyles<'button' | 'root'>(theme => ...)

Если пропущены также реквизиты, это станет

withStyles<'button' | 'root', Props>((theme, props) => ...)

Каков текущий статус этого? Было бы здорово иметь эту функцию

@lucasmafra Я добавил эту функцию к этапу выпуска post v1. Чем раньше мы выпустим v1, тем лучше.

Эта функциональность является ключом к возможности писать правила выразительного стиля, сочетающие свойства, медиа-запросы и интерактивные состояния. Вы не можете заменить эту функциональность встроенными стилями. К сожалению, withStyles нельзя использовать ни в одном из моих проектов, пока он не будет добавлен.

Вы всегда можете настроить собственную тему и использовать это соглашение: нам очень нравится, как стилизованные компоненты предоставляют вам доступ к props.theme из коробки, встраивая ThemeProvider в MuiThemeProvider, когда оба вызывают theme = {theme}. Он расширяет тему по умолчанию, которую предоставляет mui

//inline with HOC Method
 h1 style= {{ 'color: this.props.theme.palette.primary[500]' }}

//styled components ( no method necessary )
const Heading = styled.h1`
  color: ${p => p.theme.palette.primary['500']};
`

Мне просто нужно было использовать значения функций, поэтому я использовал функцию response-jss ' injectSheet() . Я привык использовать функцию Mui withStyles() , поэтому есть ли недостатки при использовании injectSheet вместо withStyles?

@ damien-monni У вас нет доступа к своей теме MUI.

Привет всем, просто хотел поделиться своей версией API, подобного компонентам в стиле Material-UI. Он не был тщательно протестирован, но, похоже, работает хорошо и обеспечивает:

  • Подняты props и theme для стилизации функции.
  • Передача пользовательского props обернутому компоненту
  • Пересылка ссылок через React.forwardRef
    (РЕДАКТИРОВАТЬ: ссылки в настоящее время работают только для тегов html, а не для большинства базовых компонентов Material-UI, для этого требуется внутренняя поддержка. Может работать над PR, когда у меня будет время, потребуется принять function или object prop-types и выполнение проверок компонентов без состояния, передавать ли их дочернему элементу)

Связанные вопросы: # 10825, # 7633

styled.js

import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';

function styled(WrappedComponent, customProps) {
  return (style, options) => {
    class StyledComponent extends Component {
      render() {
        let {
          forwardRef,
          classes,
          className,
          ...passThroughProps
        } = this.props;
        return (
          <WrappedComponent
            ref={forwardRef}
            className={classNames(classes.root, className)}
            {...passThroughProps}
            {...customProps}
          />
        );
      }
    }

    StyledComponent.propTypes = {
      classes: PropTypes.object.isRequired,
      className: PropTypes.string,
    };

    let hoistedProps = {};

    const styles =
      typeof style === 'function'
        ? theme => {
            return { root: style({ ...theme, theme, props: hoistedProps }) };
          }
        : { root: style };

    const WithRef = withStyles(styles, options)(StyledComponent);

    return React.forwardRef((props, ref) => {
      hoistedProps = props;
      return <WithRef {...props} forwardRef={ref} />;
    });
  };
}

export default styled;

Пример использования

const MobileNav = styled('nav')(({ theme, props }) => ({
  '&.pos-fixed': {
    top: 0,
    position: props.fixed ? 'fixed' : 'absolute',
    zIndex: 99,
    animation: 'fadeInDown 0.3s ease-out forwards',
    backgroundColor: theme.palette.common.white,
  },
}));

С индивидуальным реквизитом

const StyledButton = styled(Button, { component: Link })(
  ({ theme, props }) => ({
    color: props.disabled ? 'gray' : 'blue',
    [theme.breakpoints.down('sm')]: {
      color: 'red',
    },
  })
);

@oliviertassinari Чтобы решить эту проблему, я использую следующее решение:

    componentWillMount() {
        const {color} = this.props;
        jss.setup(jssPreset());
        const stylesheet = jss.createStyleSheet({
            underline: {
              "&:after": {
                backgroundColor: `${color} !important`
              }
            }
        }).attach();
        this.underlineClass = stylesheet.classes.underline;
    }

Он отлично работает, но есть ли какие-то потенциальные проблемы, которых я не вижу? Мне не нравится, что мне нужно дважды вызывать jss.setup, например 😅. Я не уверен, что понимаю жизненный цикл jss . Я был удивлен, что здесь мне нужно было вызвать setup() .

Он отлично работает, но есть ли какие-то потенциальные проблемы, которых я не вижу?

@wcandillon Некоторые потенциальные проблемы, которые я вижу: 1. Вы будете вводить новые имена классов каждый раз, когда монтируется экземпляр компонента. 2. Вы не сможете выполнить рендеринг компонента на стороне сервера. 3. Вы не получите правильный порядок вставки переопределения CSS.

Я разработал эту библиотеку, чтобы иметь стильный реквизит:

https://github.com/JacquesBonet/jss-material-ui

Успешно протестирован на проекте.

Сначала я использую решение danielmahon, но получаю проблему наследования стиля.

@oliviertassinari Есть ли у нас альтернативный подход для создания динамических CSS / анимаций на данный момент? Спасибо :)

@HunderlineK Некоторые альтернативы: https://material-ui.com/customization/overrides/#2 -dynamic -iversity-for-a-one-time-scheme.

@danielmahon, ваш подход - это именно то, что я ищу прямо сейчас, чтобы решить мою проблему, хотя «Стилизованный компонент» не перерисовывается, когда он получает новые реквизиты. Вы пробовали что-нибудь еще?

Я подумаю о другом, и если что-то придумаю, я дам тебе знать

💰 Только что назначил вознаграждение в размере 50 долларов :)

https://www.bountysource.com/issues/47838203-withstyles-add-the-ability-to-get-the-component-s-props-from-within-the-style-object

Как сказал @lewisdiamond , const styles = (props, theme) => ({}) было бы действительно здорово.

Или const styles = (theme, props) => ({}) чтобы быть неразрывным.

Я добавляю эту проблему в этап v1.x. Многие люди этого просят. Мы скоро к этому дойдем.

capture d ecran 2018-07-29 a 13 12 03

@oliviertassinari, это, вероятно, имеет серьезные последствия для ввода withStyles , дайте мне знать, могу ли я помочь с этим

@pelotom Спасибо, я дам вам знать. Я надеюсь, что смогу начать изучение вопроса в этом месяце.

Ведется ли работа по этому поводу? Это ключевая особенность, ИМО, может быть, я смогу с ней помочь.

РЕДАКТИРОВАТЬ: Я начал над этим работать. Удалось передать реквизиты функции styles которую принимает withStyles , единственная проблема в том, что стили не обновляются при изменении реквизита. Создадим пиар, когда это будет решено.

Привет, я только что наткнулся на вариант использования, в котором мне нужно было настроить цвета компонента аватара, и нет другого способа контролировать стиль для всех вариантов компонента, кроме этого.

const styles = theme => ({
  chip:{
  },
  separator: {
    marginRight: theme.spacing.unit,
  },
  fright: {
    float: 'right',
  },
  fleft: {
    float: 'left',
  },
  outlinedPrimary:{
    color: props =>  stringToColor( props.username),
    border: props => `1px solid ${fade(stringToColor(props.username), 0.5)}`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      border: `1px solid ${stringToColor(props.username)}`,
      }),
  },
  outlined: {
    backgroundColor: 'transparent',
    border: props => `1px solid ${
      theme.palette.type === 'light' ? stringToColor(props.username) : fade(stringToColor(props.username))
    }`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      }),
    },
});

Вы можете проверить мое решение Japrogramer: https://github.com/JacquesBonet/jss-material-ui

спасибо, я посмотрю на это.

Сегодня мне нужна была эта функция, поэтому я написал HOC. withStyles выполняет кеширование, поэтому я не могу точно сказать, насколько это повлияет на это, но я посмотрю на реализацию кеширования withStyles в свободное время, пока любой, кто ищет быстрый способ получить реквизит и тему, чтобы хорошо поиграть

Предупреждение

Этот компонент выполнит полное перемонтирование, если реквизиты изменят что-то, связанное с изменением номера индекса класса таблицы стилей или чем-то в withStyles HOC.

import React from 'react';
import { withStyles } from '@material-ui/core/styles';

const { createElement, forwardRef } = React

const withPropsStyles = ( style ) => {

    const withPropsStyles = ( component ) => {

        return forwardRef( (props, ref) => {

            const proxy = (theme) => style(props, theme)

            const hoc = withStyles(proxy)(component)

            return props.children ? 
                createElement(hoc, { ...props, ref}, props.children) :
                createElement(hoc, {...props, ref}) 
        }) 
    }

    return withPropsStyles
}

export default withPropsStyles

Пример использования

const styles = (props, theme) => ({
    root:{
        backgroundColor: props.light ? theme.palette.primary.light : theme.palette.primary.main 
    },
})

const SomeComponent = ({classes}) => <div className={classes.root}/>

export default withPropsStyles(styles)(SomeComponent)

заключение

Просто и работает (но оставьте полную стоимость перемонтажа)

С этим изменением мы можем удалить использование встроенных стилей из библиотеки в пользу 100% JSS? Мое приложение не работает со встроенными стилями, и когда я решил заменить эффект ряби на JSS, я понял, что мне нужна эта функция. Возможно небольшое снижение производительности, но кажется чище.

@koshea откажется от встроенного стиля. Мне также очень не нравятся встроенные стили, они должны отлично работать в качестве замены withStyles в качестве декоратора или как в примере.

Я также хотел упомянуть, что использование встроенных стилей не позволяет включить сильную политику безопасности контента.
Это требует добавления флага unsafe-inline к директивам стилей, что небезопасно.

Динамические стили с поддержкой реквизита должны решить эту проблему.

Привет, ребята, извините за участие в обсуждении «вот так». Недавно я начал использовать Mui (с Typescript), и хотя я считаю его чрезвычайно мощной библиотекой, в ней, безусловно, есть свои сложности.

В некоторых комментариях выше я заметил, что ведется небольшая дискуссия о том, должна ли эта функция быть (props, theme) => {} или (theme, props) => {} . Я хотел бы подкрепить то, что @pelotom сказал о создании props и theme в своем комментарии . Это, вероятно, упростит нам рефакторинг определений стилей после того, как произойдет это изменение (чего я действительно с нетерпением жду). Ура 🙂

Всем спасибо за терпение! Эта проблема решается в # 13503. Это требование к помощникам компонентов, которые мы хотим реализовать. Мы также начали экспериментировать с API хуков: https://twitter.com/olivtassinari/status/1058805751404261376.

Это вошло в 4.0? Похоже, что обратный вызов makeStyles не имеет параметра props .

@ city41 const classes = useStyles(props);

Понятно. Так что похоже, что это

const useStyles = makeStyles(theme => {
    return {
        foo: {
            color: theme.props.danger ? '#ff0000' : '#00ff00'
        }
    };
});

function MyComponent(props) {
    const classes = useStyles(props);

    return <div className={classes.foo}>...</div>;
}

Я не вижу этого документированного в разделе API стилей на веб-сайте. Дай мне посмотреть, смогу ли я отправить пиар.

@ city41 Начало документации находится в https://material-ui.com/styles/basics/#adapting -based-on-props.

круто, рад видеть, что документы обновляются. для всех, кто сталкивается с этой проблемой, вот как я объединил тему и реквизиты для стилизации компонента.

import React from 'react';
import { Button, Theme, makeStyles } from '@material-ui/core';

interface ButtonProps {
    destructive: boolean;
}

const useButtonStyles = makeStyles<Theme, ButtonProps>(theme => {
    return {
        root: props => ({
            backgroundColor: props.destructive ? theme.palette.error.main : theme.palette.primary.main
        })
    };
});

export const PrimaryButton: React.FunctionComponent<ButtonProps> = props => {
    const classes = useButtonStyles(props);

    return <Button {...props} className={classes.root} variant="contained" />;
};

Как я могу использовать опору во внешнем файле стилей json?

например это внешний файл

const typographyStyle = {
  title2: {
    fontFamily:"Montserrat",
    fontStyle:"normal",
    fontWeight:"800",
    fontSize:"72px",
    lineHeight:"88px",
    letterSpacing:"-0.02em",
    // color:"#304C82"
    color : props => {
      console.log(props,'c1');
      return props.color
    }

  }
};

export default typographyStyle;

я импортирую этот файл и выкладываю объект

import typographyStyle from "../assets/jss/material-kit-pro-react/views/componentsSections/typographyStyle";


const styles = theme =>  ({
    ...typographyStyle,
    homeSearch:{
        width: '100%',
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    },

  });

теперь на функции цвета я получаю props = {}.

может кто-нибудь мне в этом помочь?

ОБНОВИТЬ:

похоже, что я делаю что-то не так, потому что я получаю пустой объект даже в моем основном файле styles.js

    homeSearch: props => {
        console.log(props);
        return {
        width: '100%',
        border:  `1px solid ${props.color}`
        ,
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    }
},
Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

mnajdova picture mnajdova  ·  105Комментарии

iceafish picture iceafish  ·  62Комментарии

chadobado picture chadobado  ·  119Комментарии

NonameSLdev picture NonameSLdev  ·  56Комментарии

tdkn picture tdkn  ·  57Комментарии