0

Here's the code:

export default class Collage extends React.Component {
    constructor() {
        super();
        this.state = {
            images: [
                <this.Image src="" />,
            ],
        };
    }

    Image = ({ src }) => (
        <img className="collage__img" alt="" src={src} onTransitionEnd={evt => evt.target.remove()} />
    );

    render() {
        return (
            <div className="collage">
                {this.state.images}
            </div>
        );
    }
}

All I want is to generate a list of images in .collage block before everything is rendered. As you see, I tried to create images in the constructor. But this way I get an error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

But if I declare Image in the constuctor (without using this) everything works fine. Such a strange behavior.

Could you tell, is there another way to generate data before render?

1
  • How many images do you want to generate? In the images array there's only one item. Commented Aug 2, 2020 at 14:14

4 Answers 4

1

Create your Image component class outside of College.js. Also remember to add in a "key" attribute on JSX which are stored in array to help react run faster.

Codesandbox

Image.js

import React from "react";
const Image = ({ src }) => (
  <img
    className="collage__img"
    alt=""
    src={src}
    onTransitionEnd={evt => evt.target.remove()}
  />
);

export default Image;

College.js

import React from "react";
import Image from "./Image";

export default class Collage extends React.Component {
  constructor() {
    super();
    this.state = {
      images: [
        <Image
          key="a356f8ff-0fc4-4c00-afb4-8ce60fcc210e"
          src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Test-Logo.svg/1200px-Test-Logo.svg.png"
        />
      ]
    };
  }

  render() {
    return <div className="collage">{this.state.images};</div>;
  }
}

App.js

import React from "react";
import "./styles.css";
import Collage from "./College";

export default function App() {
  return (
    <div className="App">
      <Collage />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

1

I don't know why you don't put <Image /> as separate component since it doesn't depend on anything in your class context as below:

const Image = ({ src }) => (
  <img className="collage__img" alt="" src={src} onTransitionEnd={evt => evt.target.remove()} />
);

class Collage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        images: [
          <Image src="" />
        ],
    };
  }

  render() {
    return (
        <div className="collage">
          {this.state.images}
        </div>
    );
  }
}

Comments

1

I don't know why you want to put your components in the state but this is not optimized. I think the best way to do that is somethink like this:

  export default class Collage extends React.Component {
        constructor() {
            super();
            this.state = {
                images: [
                    {src: ""}
                ],
            };
        }
    
        Image = ({ src }) => (
            <img className="collage__img" alt="" src={src} onTransitionEnd={evt => evt.target.remove()} />
        );
    
        render() {
            return (
                <div className="collage">
                    {this.state.images.map(this.Image)}
                </div>
            );
        }
    }

Comments

-1

You can use react lifecycle method componentWillMount() which will generate a list of images in .collage block before everything is rendered.

1 Comment

componentWillMount has been deprecated in ReactJs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.