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?


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


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

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>

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>

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.


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.


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>

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.


5

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

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

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/


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>

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.


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

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>

3
React ne prend pas en charge les tableaux depuis le début et maintenant il ne fonctionne plus.
witoong623
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.