Search code examples
cssreactjsdomcomponentsgetcomputedstyle

Trying to getComputedStyle from parent element/Component in React


I need to get computed background color a parent element to pass to an Image component. This is needed as I'm using the Contentful API to render images on the fly, and I have to supply a bg color query param.

Currently this isn't working:

import Card, { CardContent } from 'components/Card';
import React, { Component, PropTypes } from 'react';

import Image from 'components/Image';
import Link from 'react-router/lib/Link';

export default class Expertise extends Component {
  
  componentDidMount()   {
    console.log(window.getComputedStyle(this._bg, null).getPropertyValue('backgroundColor'));
  }
  
  _renderColumned() {
    return (
      <Card
        layout={this.props.layout}
        additionalClasses={['expertise-item-container']}
        automationId={`expertise-container-${this.props.id}`}
        ref={node => (this._bg = node)}
      >
        <CardContent layout={'text'} theme={'transparent'} padded>
          <h3 className="expertise-headline h4" data-automation={`expertise-headline-${this.props.id}`}>
            <span className="h1 card-grid-enumeration">{this.props.displayNumber}</span>
            {this.props.headline}
          </h3>
          <p className="expertise-description" data-automation={`expertise-description-${this.props.id}`}>{this.props.description}</p>
          { this.props.url && this.props.linkText ?
            <Link className="expertise-link" data-automation={`expertise-link-${this.props.id}`} to={this.props.url}>{this.props.linkText}</Link> :
              null }
        </CardContent>
        <CardContent layout={'image'} theme={'transparent'} padded>
          <Image url={this.props.media.url} alt={this.props.media.alt} aspectRatio={'rectangle'} fit={'pad'} automationId={`expertise-image-${this.props.id}`} background={"F4F4F4"} />
        </CardContent>
      </Card>
    );
  }

  _renderStacked() {
    return (
      <div
        className="expertise-item-container centered"
        data-automation={`expertise-container-${this.props.id}`}
        // ref={image => (this._image = image)}
        ref={node => (this._bg = node)}
      >
        <h3 className="expertise-headline h4" data-automation={`expertise-headline-${this.props.id}`}>
          <span className="h1 card-grid-enumeration">{this.props.displayNumber}</span>&nbsp;
          {this.props.headline}
        </h3>
        <p className="expertise-description" data-automation={`expertise-description-${this.props.id}`}>{this.props.description}</p>
        <Image url={this.props.media.url} alt={this.props.media.alt} aspectRatio={'banner'} fit={'pad'} automationId={`expertise-image-${this.props.id}`} ref={node => (this._image = node)} background={"F4F4F4"} />
        { this.props.url && this.props.linkText ?
          <Link className="expertise-link" data-automation={`expertise-link-${this.props.id}`} to={this.props.url}>{this.props.linkText}</Link> :
            null }
      </div>
    );
  }

  render() {
    return this.props.layout === 'columned' ?
      this._renderColumned() :
      this._renderStacked();
  }

}

Expertise.propTypes = {
  id: PropTypes.string.isRequired,
  layout: PropTypes.oneOf(['columned', 'stacked']).isRequired,
  headline: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  media: PropTypes.object.isRequired,
  url: PropTypes.string,
  linkText: PropTypes.string,
  displayNumber: PropTypes.number.isRequired
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Specifically, getComputedStyle reports Uncaught TypeError: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.

Just trying to get the background-color successfully, eventually I would compare this to the default given in the background prop to the Image component.


Solution

  • I think the problem is that you can't get computed styles before component has been rendered (the same reason you can't get ref). You can store a parent bgcolor style in its local state (it will be null or undefined ot white at the beginning, whatever) and pass it to component's children. After the component has been rendered (componentDidMount() or window.addEventListener("load", ...)) you can call parent setState() method to set its bgcolor state (). Then this component will be rerendered and its children will access its bgcolor.