Home » Reactjs » How to combine multiple inline style objects?

How to combine multiple inline style objects?

Posted by: admin November 30, 2017 Leave a comment

Questions:

In React you can clearly create an object and assign it as an inline style. i.e.. mentioned below.

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

How can I combine multiple objects and assign them together?

Answers:

You can use the spread operator:

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

Questions:
Answers:

If you’re using React Native, you can use the array notation:

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

See the docs for more info.

Questions:
Answers:

You can do this with Object.assign().

In your example, you would do:

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

That will merge the two styles. The second style will replace the first if there are matching properties.

As Brandon noted, you should use Object.assign({}, divStyle, divStyle2) if you want to reuse divStyle without the fontSize applied to it.

I like to use this to make components with default properties. For example, here’s a little stateless component with a default margin-right:

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

So we can render something like this:

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

Which will give us the result:

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

Questions:
Answers:

Object.assign() is an easy solution, but the (currently) top answer‘s usage of it–while just fine for making stateless components, will cause problems for the OP’s desired objective of merging two state objects.

With two arguments, Object.assign() will actually mutate the first object in-place, affecting future instantiations.

Ex:

Consider two possible style configs for a box:

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

So we want all our boxes to have default ‘box’ styles, but want to overwrite some w/ a diff’t color:

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

Once Object.assign() executes, the ‘styles.box’ object is changed for good.

The solution is to pass an empty object to Object.assign(). In so doing, you’re telling the method to produce a NEW object with the objects you pass it. Like so:

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

This notion of objects mutating in-place is critical for React, and proper use of Object.assign() is really helpful for using libraries like Redux.

Questions:
Answers:

So basically I’m looking at this in the wrong way. From what I see, this is not a React specific question, more of a JavaScript question in how do I combine two JavaScript objects together (without clobbering similarly named properties).

In this StackOverflow answer it explains it. How can I merge properties of two JavaScript objects dynamically?

In jQuery I can use the extend method.

Questions:
Answers:

To Expand on what @PythonIsGreat said, I create a global function that will do it for me:

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

This deeply extends the objects into a new object and allows for a variable number of objects as parameters. This allows you to do something like this:

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

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

Questions:
Answers:

I have built an module for this if you want to add styles based on a condition
like this:

multipleStyles(styles.icon, { [styles.iconRed]: true })

https://www.npmjs.com/package/react-native-multiple-styles