Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting background image as prop in react

Tags:

reactjs

I have a react component that needs to take in a background image from the parent Play component, not set in the stylesheet. I'm trying to pass it as a prop to the component, but not sure quite sure how to get this working:

Main component

import React from 'react'
import ReactDOM from 'react-dom'
import DeviceBlock from '/DeviceBlock/DeviceBlock'

const Play = {
  init() {
    const container = document.getElementById('blocker-container');
    if(container) {
      ReactDOM.render(
        <DeviceBlock
        backgroundImage={'background-image-url.png'}
        logo={'url-to-logo.png'} />,
        container
      )
    }
  }
}

document.addEventListener('DOMContentLoaded', () => {
  Play.init()
})

Blocking component imported into above Play component

import React from 'react'
import './DeviceBlock.scss'

function DeviceBlock (props) {
  constructor(props) {
    super(props)
    this.state = {
      backgroundImage: backgroundImage,
      logo: logo;
    }
  }
  return (
    <div className='device-blocking' style={this.state.backgroundImage}>
      <div className='container'>
        <div className='logo'>
          <img src='{{this.state.logo}}' />
        </div>
        <div className='message'>
          <h1>Content</h1>
          <a href='/' className='btn btn--primary btn--lg'>Link</a>
        </div>
      </div>
    </div>
  )
}

export default DeviceBlock
like image 349
Matt Avatar asked Apr 09 '18 19:04

Matt


2 Answers

You should import your background img

import BackgroundImage from '...png'; // Relative Path to BackgroundImage
import Logo from '...png'; // Relative Path to Logo

and in your state

this.state = {
  backgroundImage: `url(${BackgroundImage})`,
  logo: Logo
};

Also I noticed that your <img> is wrong

<img src='{{this.state.logo}}' />

Should be

<img src={this.state.logo} />

Also note I saw that you added a constructor inside a function. If you want to create a react component with state you need to make the component a class.

class DeviceBlock extends React.Component { 
  constructor(props) {
    super(props);
    this.state = {}
  }
  render() { 
    ...
  }
}

EDIT: This is the updated code for your edit based on passing through props.

import React from 'react'
import ReactDOM from 'react-dom'
import DeviceBlock from '/DeviceBlock/DeviceBlock'
import BackgroundImage from '../url-to-background.png'; // Path to BackgroundImage
import Logo from 'url-to-logo.png'; // Relative Path to Logo

const Play = {
  init() {
    const container = document.getElementById('blocker-container');
    if (container) {
      ReactDOM.render(
        <DeviceBlock
          backgroundImage={BackgroundImage}
          logo={Logo} 
        />,
        container
      )
    }
  }
}

document.addEventListener('DOMContentLoaded', () => {
  Play.init()
})

import * as React from 'react'
import './DeviceBlock.scss'

function DeviceBlock (props) {
  return (
    <div 
      className='device-blocking' 
      style={{ backgroundImage: `url(${props.backgroundImage})` }}
    >
      <div className='container'>
        <div className='logo'>
          <img src={props.logo} />
        </div>
        <div className='message'>
          <h1>Content</h1>
          <a href='/' className='btn btn--primary btn--lg'>Link</a>
        </div>
      </div>
    </div>
  );
}

export default DeviceBlock

Note my solution only works if your images are from your own server and processed from webpack and not from another URL.

If the images are from another URL you shouldn't import the URLs and add them directly to the props

<DeviceBlock
  backgroundImage="url-to-background.png",
  logo="url-to-logo.png"
/>
like image 91
Kenneth Truong Avatar answered Oct 29 '22 06:10

Kenneth Truong


Style is an object. Try it like this:

style={{backgroundImage: this.state.backgroundImage}}

Further, you cannot have a constructor and use state within a functional component. Either turn your component into a regular react component and keep the state, or have the state part in a regular react component and pass it down as props into the functional component. This is also mentioned in the answer by @Kenneth Truong

To turn it into a regular react component you can do the following:

class DeviceBlock extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      backgroundImage: "url('url-to-background.png')",
      logo: "url('url-to-logo.png')";
    }
  }
  render() {
    return (
      <div className='device-blocking' style={{backgroundImage: this.state.backgroundImage}}>
        <div className='container'>
          <div className='logo'>
            <img src='{{this.state.logo}}' />
          </div>
          <div className='message'>
            <h1>Content</h1>
            <a href='/' className='btn btn--primary btn--lg'>Link</a>
          </div>
        </div>
      </div>
    )
  }
}

You can see it working here: https://codepen.io/anon/pen/zWexzO

UPDATE

Based on the updated question, you can also keep it as a functional component and pass down props:

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      backgroundImage: "url('url-to-background.png')",
      logo: "url('url-to-logo.png')";
    }
  }
  render() {
    return (
      <DeviceBlock 
        backgroundImage={this.state.backgroundImage}
        logo={this.state.logo}/>
    )
  }
}

const DeviceBlock = (props) => {
    return (
      <div className='device-blocking' style={{backgroundImage: props.backgroundImage}}>
        <div className='container'>
          <div className='logo'>
            <img src='{{props.logo}}' />
          </div>
          <div className='message'>
            <h1>Content</h1>
            <a href='/' className='btn btn--primary btn--lg'>Link</a>
          </div>
        </div>
      </div>
    )
} 

https://codepen.io/anon/pen/OvdPOQ

The app component is simply demonstrating that you can pass down some dynamic state. You can, of course, render the DeviceBlock component directly from your Play.init function like you do in your provided code (then you can just ignore the App component part).

like image 5
the_cheff Avatar answered Oct 29 '22 06:10

the_cheff