Comment combiner plusieurs objets de style en ligne?

214

Dans React, vous pouvez clairement créer un objet et l'affecter en tant que style en ligne. c'est à dire. mentionné ci-dessous.

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);

Comment puis-je combiner plusieurs objets et les affecter ensemble?

PythonIsGreat
la source
À quoi ressemblent les deux objets?
Ryan

Réponses:

399

Si vous utilisez React Native, vous pouvez utiliser la notation de tableau:

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

Consultez mon blog détaillé à ce sujet.

pseudo
la source
41
Malheureusement, vous ne pouvez pas faire cela dans React régulier.
YoTengoUnLCD
8
Cela devrait être la réponse acceptée si vous utilisez React-Native
calcazar
Vous pouvez légèrement modifier le style en ligne existant en ajoutant les noms / valeurs de style. Par exemple,<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
Gürol Canbek
Pour deux styles statiques, faire en StyleSheet.compose()dehors de la fonction de rendu peut être plus efficace. Il produira une nouvelle feuille de style statique qui ne sera envoyée qu'une fois sur le pont. (Ce conseil ne s'applique pas aux styles qui changent au moment de l'exécution, ou qui sont en ligne plutôt que dans une feuille de style.)
joeytwiddle
282

Vous pouvez utiliser l'opérateur d'étalement:

 <button style={{...styles.panel.button,...styles.panel.backButton}}>Back</button
Nath
la source
8
J'obtiens "Erreur de syntaxe: jeton inattendu", pointant vers le premier point du premier opérateur d'étalement.
Izkata
@Izkata Faites-vous cela en réagissant ou en réagissant natif, pourriez-vous publier votre extrait
Nath
Réagissez, c'était quelque chose comme<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata
Je l'ai quand même changé pour utiliser une fonction d'aide comme de <div style={LEGEND_STYLE.box_gen('#123456')}toute façon, donc ce n'est pas un gros problème pour moi
Izkata
Cela fonctionne même si l'objet n'a qu'une seule paire clé-valeur, même si les opérateurs répartis ne sont censés être valides que pour les itérables! Pouvez-vous expliquer pourquoi? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Tyler
47

Vous pouvez le faire avec Object.assign().

Dans votre exemple, vous feriez:

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

Cela fusionnera les deux styles. Le deuxième style remplacera le premier s'il existe des propriétés correspondantes.

Comme l'a noté Brandon, vous devez l'utiliser Object.assign({}, divStyle, divStyle2)si vous souhaitez réutiliser divStylesans que la taille de police ne lui soit appliquée.

J'aime l'utiliser pour créer des composants avec des propriétés par défaut. Par exemple, voici un petit composant sans état avec une valeur par défaut margin-right:

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

Nous pouvons donc rendre quelque chose comme ceci:

<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>

Ce qui nous donnera le résultat:

<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
la source
5
cette solution est potentiellement utilisée Object.assign()à mauvais escient d'une manière qui entraînerait des conséquences indésirables. Voir la réponse ici une solution plus fiable.
Brandon
1
Votre réponse illustre un moyen d'abuser de Object.assign (). Ces informations peuvent être utiles pour certaines personnes, mais elles ne s'appliquent pas à mon exemple. Cet exemple ne stocke pas la valeur par défaut dans un objet, le mute, puis réutilise l'objet muté ailleurs.
2016
être en désaccord. vous abordez deux façons distinctes d'utiliser Object.assign()dans votre réponse. la première, dans les premières phrases, est un exemple de la mauvaise utilisation que j'ai identifiée (c'est-à-dire que si OP a fait ce que vous conseillez dans votre premier codebloc, il / elle muterait {divStyle}). la deuxième façon - c'est-à-dire, l'enrouler dans une fonction comme vous l'avez, fonctionnera, mais la réponse ne précise pas que vous travaillez autour Object.assign() de l'immuabilité «gotcha» commune de wrt (bien que personnellement, je pense que c'est un peu encombrant pour écrire une fonction sans état personnalisée pour chaque composant par défaut).
Brandon
Ah d'accord. C'est vrai. S'il voulait réutiliser divStyle sans appliquer le fontSize, il aurait d'abord besoin de l'objet vide. Je mettrai à jour la réponse.
qel
Object.assign () est de loin le moyen le plus pratique pour réaliser une concaténation :)
aldobsom
29

Contrairement à React Native, nous ne pouvons pas transmettre un tableau de styles dans React, comme

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

Dans React, nous devons créer l'objet unique des styles avant de le passer à la propriété style. Comme:

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

  let enhancedStyle = {
    fontSize: '38px'
  }

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

Nous avons utilisé l' opérateur Spread ES6 pour combiner deux styles. Vous pouvez également utiliser Object.assign () dans le même but.

Cela fonctionne également si vous n'avez pas besoin de stocker votre style dans un var

<Segment style={{...segmentStyle, ...{height:'100%'}}}>
    Your content
</Segment>
achyut pokhrel
la source
Nous ne pouvons pas passer le tableau au style?
heisenberg
3
Juste pour ajouter à votre dernier extrait, {{... segmentStyle, height: '100%'}} fonctionnera également.
Luke Brandon Farrell
26

Object.assign()est une solution facile, mais son utilisation (actuellement) la meilleure réponse - bien qu'elle soit très bien pour créer des composants sans état, causera des problèmes pour l'objectif souhaité de l'OP de fusionner deux stateobjets.

Avec deux arguments, Object.assign()va en fait muter le premier objet en place, affectant les instanciations futures.

Ex:

Considérez deux configurations de style possibles pour une boîte:

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

Nous voulons donc que toutes nos boîtes aient des styles de boîte par défaut, mais nous voulons en remplacer certaines avec une couleur différente:

// 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>

Une fois Object.assign()exécuté, l'objet 'styles.box' est définitivement changé.

La solution est de passer un objet vide à Object.assign(). Ce faisant, vous dites à la méthode de produire un nouvel objet avec les objets que vous lui avez transmis. Ainsi:

// 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>

Cette notion d'objets en mutation sur place est critique pour React, et une bonne utilisation de Object.assign()est vraiment utile pour utiliser des bibliothèques comme Redux.

Brandon
la source
1
Votre exemple d'utilisation abusive d'Object.assign n'est pas une représentation valide de la façon dont Object.assign est utilisé dans la réponse (actuellement) supérieure.
qel
merci, modifications apportées pour refléter quel aspect est (actuellement) une mauvaise utilisation
Brandon
1
joli morceau de code juste là. Object.assign ({}, this.state.showStartOverBtn? {}: This.hidden, this.btnStyle)} les conditionnelles fonctionnent également comme un charme
steveinatorx
17

Array notaion est le meilleur moyen de combiner des styles dans React Native.

Cela montre comment combiner 2 objets Style,

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

cela montre comment combiner objet et propriété Style,

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

Cela fonctionnera sur n'importe quelle application native React.

Sasindu Lakshitha
la source
2
Les questions sont pour React, pasReact Native
Dimitar Tsonev
Vous pouvez également l'utiliser pour React
Sasindu Lakshitha
React ne prend pas en charge les tableaux depuis le début et maintenant il ne fonctionne plus.
witoong623
réagir ne supporte pas encore le style de combinaison comme celui-ci.
kiwi en colère
12

Vous pouvez également combiner des classes avec un style en ligne comme ceci:

<View style={[className, {paddingTop: 25}]}>
  <Text>Some Text</Text>
</View>
Gil Perez
la source
8

En fait, il existe un moyen formel de combiner et c'est comme ci-dessous:

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

Mais, il y a un petit problème , si l'un d'eux est passé par le composant parent et qu'il a été créé par une manière formelle combinée, nous avons un gros problème:

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

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

Et cette dernière ligne a un bug d'interface, sûrement, React Native ne peut pas gérer un tableau profond à l'intérieur d'un tableau. Je crée donc ma fonction d'aide:

import { StyleSheet } from 'react-native';

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

En utilisant my styleJoinerpartout, vous pouvez combiner n'importe quel type de style et combiner des styles. même undefinedou d'autres types inutiles ne provoquent pas de rupture du style.

AmerllicA
la source
5

J'ai trouvé que cela fonctionnait le mieux pour moi. Il remplace comme prévu.

return <View style={{...styles.local, ...styles.fromProps}} />
Adrian Bartholomew
la source
2

Pour ceux qui recherchent cette solution dans React, si vous souhaitez utiliser l'opérateur de propagation dans le style, vous devez utiliser: babel-plugin-transform-object-rest-spread.

Installez-le par le module npm et configurez votre .babelrc comme tel:

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

Ensuite, vous pouvez utiliser comme ...

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

Plus d'informations: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-spread/

Phénix
la source
2

Pour aller encore plus loin, vous pouvez créer une fonction d'assistance semblable à des noms de classe :

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

Et puis utilisez-le conditionnellement dans vos composants:

<div style={

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

}>Hello World!</div>
strelettes
la source
0

Donc, fondamentalement, je regarde les choses dans le mauvais sens. D'après ce que je vois, ce n'est pas une question spécifique à React, plus une question JavaScript sur la façon de combiner deux objets JavaScript ensemble (sans encombrer des propriétés nommées de manière similaire).

Dans cette réponse StackOverflow, il l'explique. Comment fusionner dynamiquement les propriétés de deux objets JavaScript?

Dans jQuery, je peux utiliser la méthode extend.

PythonIsGreat
la source
1
La fusion d'objets ne suffit pas lorsque vous travaillez avec des objets contenant des styles CSS. Il existe des propriétés de raccourci, des majuscules différentes, etc. qui doivent être traitées dans le bon ordre par la fonction de fusion. Je cherche et je n'ai pas encore trouvé de bibliothèque qui offre une telle fonction.
sompylasar
Voici une bibliothèque qui fait une extension de propriété abrégée: github.com/kapetan/css-shorthand-expand , mais ce n'est pas une solution complète.
sompylasar
0

Pour développer ce que @PythonIsGreat a dit, je crée une fonction globale qui le fera pour moi:

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

Cela étend profondément les objets dans un nouvel objet et permet un nombre variable d'objets comme paramètres. Cela vous permet de faire quelque chose comme ceci:

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

var styles = {
  base:{
    //whatever
  },
  first:{
    //whatever
  },
  second:{
    //whatever
  }
}
timthez
la source
Une simple fonction de fusion d'objets n'est pas suffisante lorsque vous travaillez avec des objets contenant des styles CSS. Voir mon commentaire à la réponse ci-dessus.
sompylasar
0

Façons de style en ligne:

<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>
lui
la source
3
React ne prend pas en charge les tableaux depuis le début et maintenant il ne fonctionne plus.
witoong623