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?

PythonIsGreat
fonte
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.

usuario
fonte
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
Nath
fonte
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>
qel
fonte
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>
achyut pokhrel
fonte
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.

Brandon
fonte
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.

Sasindu Lakshitha
fonte
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>
Gil Perez
fonte
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.

AmerllicA
fonte
5

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

return <View style={{...styles.local, ...styles.fromProps}} />
Adrian Bartholomew
fonte
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/

Fénix
fonte
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>
streletss
fonte
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.

PythonIsGreat
fonte
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
  }
}
timthez
fonte
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>
ele
fonte
3
O React não suporta array desde o início e agora não funciona mais.
Witoong623