In React, how to pass a dynamic variable to a const CSS Style list?
Asked Answered
H

2

11

I'm using react-dropzone to allow a user to upload a profile photo.

I define the custom CSS like so:

const dropzoneStyle = {
  width: `200px`,
  height: `200px`,
  backgroundColor: `#1DA1F2`,
};

Inside the method to render the DropZone input, I can detect if their is a file preview which is populated after a user selects an image to be uploaded..

What I want to do is, if the file.preview exists, send the file.preview the the dropzoneStyle so a background-image is added to the CSS.

const renderDropzoneInput = (field) => {
  const files = field.input.value;
  let dropzoneRef;

  if (files[0]) {
    console.log(files[0].preview)
  }

  return (
    <div>
      <Dropzone
        name={field.name}
        ref={(node) => { dropzoneRef = node; }}
        accept="image/jpeg, image/png"
        style={dropzoneStyle}
      >

How can I pass files[0].preview to the style dropzoneStyle with React?

Hornet answered 26/6, 2017 at 1:41 Comment(0)
E
9

Assuming files[0].preview returns a file (image) URL, you should be able to set a new style and pass it to the Dropzone component.

Something along these lines:

const renderDropzoneInput = (field) => {
  const files = field.input.value;
  let dropzoneRef;

  render() {
    let dropzoneStyle = {
      width: `200px`,
      height: `200px`,
      backgroundColor: `#1DA1F2`,
    };

    if (files[0]) {
      dropzoneStyle = {
        width: `200px`,
        height: `200px`,
        backgroundColor: `#1DA1F2`,
        backgroundImage: `url(${files[0].preview})`,
        // or to use a fixed background image
        // backgroundImage: `url(/path/to/static/preview.png)`,
        backgroundPosition: `center center`,
        backgroundRepeat: `no-repeat`
      };
    }

    return (
      <Dropzone
        name={field.name}
        ref={(node) => { dropzoneRef = node; }}
        accept="image/jpeg, image/png"
        style={dropzoneStyle}
      />
    )
  }
}  

a spread operator could be used to DRY this code a bit, with:

let dropzoneStyle = {
  width: `200px`,
  height: `200px`,
  backgroundColor: `#1DA1F2`,
};

if (files[0]) {
  dropzoneStyle = {
    ...dropzoneStyle,
    backgroundImage: `url(/path/to/static/preview.png)`,
    backgroundPosition: `center center`,
    backgroundRepeat: `no-repeat`
  };
}
Elixir answered 26/6, 2017 at 2:6 Comment(3)
Thanks, this works great. Is there a way to DRY this up so the styles are not repeated?Hornet
I was adding that as you asked. Great idea!Elixir
oh that is awesome. THANK YOUHornet
Z
15

I usually just define the style as an arrow function that returns the style object, and pass in whatever parameters are needed for the style. There is a shorthand notation for returning an object literal from an arrow function that works nicely for this.

const style = () => ({});

Just remember to only use ternary operators if using the shorthand, otherwise you would just need to explicitly return an object.

So, for your style:

const dropzoneStyle = (isPreview) => ({
  width: `200px`,
  height: `200px`,
  backgroundColor: `#1DA1F2`,
  backgroundImage: (isPreview) ? 'url(/path/to/image.jpg)' : 'none',
});

This adds the image is isPreview is true, but keeps it blank if not.

Then in your component, call the function where the style goes:

return (
  <div>
    <Dropzone
      {...otherProps}
      style={ dropzoneStyle(isPreview) }
    >
  </div>
);
Zamboanga answered 26/6, 2017 at 2:7 Comment(6)
love this idea but it is return a console error Warning: Failed prop type: Invalid prop style` of type function supplied to Dropzone, expected object.`Hornet
@Hornet Are you calling the style as a function, as in using dropzoneStyle() rather than dropsoneStyle?Zamboanga
I think the issue was react-dropzone has proptypes defined and wants style to be an object not a functionHornet
Oh, right. Well, if you need to use logic in your styles elsewhere, I think this is a pretty clean way.Zamboanga
totally agree. I wish I could use it here. Thank you again for the help!!Hornet
@JoeDalton. Hi, your solution came to my help too. Just I need to ask one more thing. Is it possible to add CSS property for first-child or nth-child using this variable styled? Something like, span:first-child { border-radius: 15px 0 0 15px } ?Erl
E
9

Assuming files[0].preview returns a file (image) URL, you should be able to set a new style and pass it to the Dropzone component.

Something along these lines:

const renderDropzoneInput = (field) => {
  const files = field.input.value;
  let dropzoneRef;

  render() {
    let dropzoneStyle = {
      width: `200px`,
      height: `200px`,
      backgroundColor: `#1DA1F2`,
    };

    if (files[0]) {
      dropzoneStyle = {
        width: `200px`,
        height: `200px`,
        backgroundColor: `#1DA1F2`,
        backgroundImage: `url(${files[0].preview})`,
        // or to use a fixed background image
        // backgroundImage: `url(/path/to/static/preview.png)`,
        backgroundPosition: `center center`,
        backgroundRepeat: `no-repeat`
      };
    }

    return (
      <Dropzone
        name={field.name}
        ref={(node) => { dropzoneRef = node; }}
        accept="image/jpeg, image/png"
        style={dropzoneStyle}
      />
    )
  }
}  

a spread operator could be used to DRY this code a bit, with:

let dropzoneStyle = {
  width: `200px`,
  height: `200px`,
  backgroundColor: `#1DA1F2`,
};

if (files[0]) {
  dropzoneStyle = {
    ...dropzoneStyle,
    backgroundImage: `url(/path/to/static/preview.png)`,
    backgroundPosition: `center center`,
    backgroundRepeat: `no-repeat`
  };
}
Elixir answered 26/6, 2017 at 2:6 Comment(3)
Thanks, this works great. Is there a way to DRY this up so the styles are not repeated?Hornet
I was adding that as you asked. Great idea!Elixir
oh that is awesome. THANK YOUHornet

© 2022 - 2024 — McMap. All rights reserved.