Como combinar vários objetos de estilo embutido?


213

No React, você pode criar claramente um objeto e atribuí-lo como um estilo embutido. ie mencionado abaixo.

var divStyle = {
  color: 'white',
  backgroundImage: 'url(' + imgUrl + ')',
  WebkitTransition: 'all', // note the capital 'W' here
  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};

var divStyle2 = {fontSize: '18px'};

React.render(<div style={divStyle}>Hello World!</div>, mountNode);

Como posso combinar vários objetos e atribuí-los juntos?


Como são os dois objetos?
30715 Ryan

Respostas:


396

Se você estiver usando o React Native, poderá usar a notação de matriz:

<View style={[styles.base, styles.background]} />

Confira meu post detalhado sobre isso.


41
Infelizmente você não pode fazer isso no React regularmente.
YoTengoUnLCD

8
Esta deve ser a resposta aceita se você estiver usando Reagir-Nativo
calcazar

Você pode modificar levemente o estilo embutido existente adicionando os nomes / valores do estilo. Por exemplo,<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
Gürol Canbek 01/09

Para dois estilos estáticos, executar StyleSheet.compose()fora da função de renderização pode ser mais eficiente. Ele produzirá uma nova folha de estilo estática que será enviada apenas pela ponte uma vez. (Este conselho não se aplica aos estilos que mudam em tempo de execução, ou que estejam em linha em vez de uma folha de estilo.)
joeytwiddle

282

Você pode usar o operador spread:

 <button style={{...styles.panel.button,...styles.panel.backButton}}>Back</button

8
Recebo "Erro de sintaxe: token inesperado", apontando para o primeiro ponto no primeiro operador de propagação.
Izkata 01/07/19

@Izkata Você está fazendo isso em reagir ou reagir nativa, você pode postar o seu trecho
Nath

Reagir, era algo parecido com:<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata

Eu mudei de qualquer maneira para usar uma função auxiliar como <div style={LEGEND_STYLE.box_gen('#123456')}de qualquer maneira, por isso não é um grande negócio para mim
Izkata

Isso funciona mesmo se o objeto tiver apenas um par de valores-chave, mesmo que os operadores de propagação sejam válidos apenas para iteráveis! Você pode explicar o porquê? developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Tyler

47

Você pode fazer isso com Object.assign().

No seu exemplo, você faria:

ReactDOM.render(
    <div style={Object.assign(divStyle, divStyle2)}>
        Hello World!
    </div>,
    mountNode
);

Isso mesclará os dois estilos. O segundo estilo substituirá o primeiro se houver propriedades correspondentes.

Como Brandon observou, você deve usar Object.assign({}, divStyle, divStyle2)se desejar reutilizar divStylesem o fontSize aplicado a ele.

Eu gosto de usar isso para criar componentes com propriedades padrão. Por exemplo, aqui está um pequeno componente sem estado com um padrão margin-right:

const DivWithDefaults = ({ style, children, ...otherProps }) =>
    <div style={Object.assign({ marginRight: "1.5em" }, style)} {...otherProps}>
        {children}
    </div>;

Então, podemos renderizar algo como isto:

<DivWithDefaults>
    Some text.
</DivWithDefaults>
<DivWithDefaults className="someClass" style={{ width: "50%" }}>
    Some more text.
</DivWithDefaults>
<DivWithDefaults id="someID" style={{ marginRight: "10px", height: "20px"}}>
    Even more text.
</DivWithDefaults>

O que nos dará o resultado:

<div style="margin-right:1.5em;">Some text.</div>
<div style="margin-right:1.5em;width50%;" class="someClass">Some more text.</div>
<div style="margin-right:10px;height:20px;" id="someID">Even more text.</div>

5
esta solução é potencialmente mal utilizada Object.assign()de uma maneira que levaria a algumas conseqüências indesejáveis. Veja a resposta aqui, uma solução mais confiável.
Brandon

1
Sua resposta demonstra uma maneira de abusar de Object.assign (). Isso pode ser uma informação útil para algumas pessoas, mas não se aplica ao meu exemplo. Este exemplo não está armazenando o padrão em um objeto, modificando-o e reutilizando o objeto modificado em outro lugar.
qel 8/06/16

discordo. você aborda duas maneiras distintas de usar Object.assign()em sua resposta. a primeira, nas primeiras frases, é um exemplo do uso indevido que identifiquei (ou seja, se o OP fez o que você recomendou no seu primeiro codebloco, ele / ela sofreu uma mutação {divStyle}). a segunda maneira - ou seja, envolvê-lo em uma função como você tem, funcionará, mas a resposta não deixa claro que você está trabalhando em torno Object.assign() da imutabilidade comum do 'pegadinha' (embora pessoalmente eu ache que é um pouco difícil escrever uma função sem estado personalizada para cada componente padrão).
Brandon

Ah ok. Isso é verdade. Se ele quisesse reutilizar o divStyle sem aplicar o fontSize, seria necessário primeiro o objeto vazio. Vou atualizar a resposta.
qel

Object.assign () é de longe a forma mais conveniente para alcançar uma concatenação :)
aldobsom

29

Ao contrário do React Native, não podemos passar uma variedade de estilos no React, como

<View style={[style1, style2]} />

No React, precisamos criar o único objeto de estilos antes de passá-lo para a propriedade style. Gostar:

const Header = (props) => {
  let baseStyle = {
    color: 'red',
  }

  let enhancedStyle = {
    fontSize: '38px'
  }

  return(
    <h1 style={{...baseStyle, ...enhancedStyle}}>{props.title}</h1>
  );
}

Usamos o operador ES6 Spread para combinar dois estilos. Você também pode usar Object.assign () também para a mesma finalidade.

Isso também funciona se você não precisar armazenar seu estilo em um var

<Segment style={{...segmentStyle, ...{height:'100%'}}}>
    Your content
</Segment>

Não podemos passar a matriz para o estilo?
precisa

3
Apenas para adicionar ao seu último snippet, {{... segmentStyle, height: '100%'}} também funcionará.
Luke Brandon Farrell

26

Object.assign()é uma solução fácil, mas o uso (atualmente) da principal resposta - embora seja bom para criar componentes sem estado, causará problemas para o objetivo desejado do OP de mesclar dois stateobjetos.

Com dois argumentos, Object.assign()na verdade, o primeiro objeto será modificado, afetando instanciações futuras.

Ex:

Considere duas configurações de estilo possíveis para uma caixa:

var styles =  {
  box: {backgroundColor: 'yellow', height: '100px', width: '200px'},
  boxA: {backgroundColor: 'blue'},
};

Portanto, queremos que todas as nossas caixas tenham estilos padrão de 'caixa', mas queremos substituir alguns com uma cor diferente:

// this will be yellow
<div style={styles.box}></div>

// this will be blue
<div style={Object.assign(styles.box, styles.boxA)}></div>

// this SHOULD be yellow, but it's blue.
<div style={styles.box}></div>

Uma vez Object.assign()executado, o objeto 'styles.box' é alterado para sempre.

A solução é passar um objeto vazio para Object.assign(). Ao fazer isso, você está dizendo ao método para produzir um novo objeto com os objetos que você o transmite. Igual a:

// this will be yellow
<div style={styles.box}></div>

// this will be blue
<div style={Object.assign({}, styles.box, styles.boxA)}></div>

// a beautiful yellow
<div style={styles.box}></div>

Essa noção de objetos com mutação no local é crítica para o React, e o uso adequado de Object.assign()é realmente útil para o uso de bibliotecas como o Redux.


1
Seu exemplo de como usar incorretamente o Object.assign não é uma representação válida de como o Object.assign está sendo usado na resposta principal (atualmente).
qel 8/06/16

graças, fez edições para refletir qual aspecto é (atualmente) um desvio
Brandon

1
bom pedaço de código ali. Object.assign (? {}, This.state.showStartOverBtn {}: this.hidden, this.btnStyle)} condicionais também trabalho como um encanto
steveinatorx

17

A anotação de matriz é a melhor maneira de combinar estilos em reagir nativo.

Isso mostra como combinar 2 objetos de estilo,

<Text style={[styles.base, styles.background]} >Test </Text>

isso mostra como combinar objeto e propriedade Style,

<Text style={[styles.base, {color: 'red'}]} >Test </Text>

Isso funcionará em qualquer aplicativo nativo de reação.


2
As perguntas são para React, nãoReact Native
Dimitar Tsonev 27/02/19

Você pode usar o mesmo para Reagir também
Sasindu Lakshitha

O React não suporta array desde o início e agora não funciona mais.
Witoong623

reagir ainda não suporta combinar estilo como este.
kiwi zangado

12

Você também pode combinar classes com estilo embutido, como este:

<View style={[className, {paddingTop: 25}]}>
  <Text>Some Text</Text>
</View>

8

Na verdade, existe uma maneira formal de combinar e é como abaixo:

<View style={[style01, style02]} />

Porém, há um pequeno problema : se um deles é passado pelo componente pai e foi criado de uma maneira formal combinada, temos um grande problema:

// The passing style02 from props: [parentStyle01, parentStyle02]

// Now:
<View style={[style01, [parentStyle01, parentStyle02]]} />

E essa última linha faz com que o bug da interface do usuário, certamente, o React Native não possa lidar com uma matriz profunda dentro de uma matriz. Então, eu crio minha função auxiliar:

import { StyleSheet } from 'react-native';

const styleJoiner = (...arg) => StyleSheet.flatten(arg);

Ao usar o meu em styleJoinerqualquer lugar, você pode combinar qualquer tipo de estilo e estilos. mesmo undefinedou outros tipos inúteis não causam quebra no estilo.


5

Eu descobri que isso funciona melhor para mim. Ele substitui conforme o esperado.

return <View style={{...styles.local, ...styles.fromProps}} />

2

Para aqueles que procuram esta solução no React, se quiser usar o operador de propagação dentro do estilo, use: babel-plugin-transform-object-rest-spread.

Instale-o pelo módulo npm e configure seu .babelrc da seguinte forma:

{
  "presets": ["env", "react"],
  "plugins": ["transform-object-rest-spread"]
}

Então você pode usar como ...

const sizing = { width: 200, height: 200 }
 <div
   className="dragon-avatar-image-background"
   style={{ backgroundColor: blue, ...sizing }}
  />

Mais informações: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-spread/


2

Para levar ainda mais longe, você pode criar uma função auxiliar semelhante a um nome de classe :

const styleRules = (...rules) => {
  return rules.filter(Boolean).reduce((result, rule) => {
    return { ...result, ...rule };
  }, {});
};

E use-o condicionalmente em seus componentes:

<div style={

  styleRules(
    divStyle,
    (window.innerWidth >= 768) && divStyleMd,
    (window.innerWidth < 768) && divStyleSm
  )

}>Hello World!</div>

0

Então, basicamente, estou vendo isso da maneira errada. Pelo que vejo, essa não é uma pergunta específica do React, mais uma questão de JavaScript sobre como combinar dois objetos JavaScript (sem interferir nas propriedades com nomes semelhantes).

Nesta resposta StackOverflow, ela explica. Como mesclar propriedades de dois objetos JavaScript dinamicamente?

No jQuery eu posso usar o método extend.


1
Apenas mesclar objetos não é suficiente ao trabalhar com objetos que contêm estilos CSS. Existem propriedades taquigráficas, letras maiúsculas e minúsculas diferentes, etc., que devem ser manuseadas na ordem correta pela função de mesclagem. Estou procurando e ainda não encontrei uma biblioteca que ofereça essa função.
sompylasar 6/09/2015

Aqui está uma biblioteca que faz a expansão abreviada de propriedades: github.com/kapetan/css-shorthand-expand , mas essa não é uma solução completa.
sompylasar

0

Para expandir o que o @PythonIsGreat disse, crio uma função global que fará isso por mim:

var css = function(){
    var args = $.merge([true, {}], Array.prototype.splice.call(arguments, 0));
    return $.extend.apply(null, args);
}

Isso estende profundamente os objetos para um novo objeto e permite um número variável de objetos como parâmetros. Isso permite que você faça algo assim:

return(
<div style={css(styles.base, styles.first, styles.second,...)} ></div>
);

var styles = {
  base:{
    //whatever
  },
  first:{
    //whatever
  },
  second:{
    //whatever
  }
}

Uma função simples de mesclagem de objetos não é suficiente ao trabalhar com objetos que contêm estilos CSS. Veja meu comentário para a resposta acima.
sompylasar 6/09/2015


0

Maneiras de estilizar em linha:

<View style={[styles.red, {fontSize: 25}]}>
  <Text>Hello World</Text>
</View>

<View style={[styles.red, styles.blue]}>
  <Text>Hello World</Text>
</View>

  <View style={{fontSize:10,marginTop:10}}>
  <Text>Hello World</Text>
</View>

3
O React não suporta array desde o início e agora não funciona mais.
Witoong623
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.