0

I have a component looks something like this:

<ImageComponent
    image={this.props.data.image1}
/>
<ImageComponent
    image={this.props.data.image2}
/>
<ImageComponent
    image={this.props.data.image3}
/>

What I am trying to do is render this component which has multiple images in a dynamic order based on data that I have before hand.

[{
    img: image1,
    placementIndex: 2
},
{
    img: image2,
    placementIndex: 0
}
{
    img: image3,
    placementIndex: 1
}]

I dont think the way I have tried is very efficient

const imageComponentPlacement = [];
this.props.componentOrder.map((placement) => {
    const componentToUse = (<ImageComponent
        image={this.props.data[placement.img]}              
    />);
    imageComponentPlacement.splice(placement.placementIndex, 0, componentToUse);
}

return imageComponentPlacement.map((NewImagePlacement, index) =>
    <div key={index}>
        <NewImagePlacement />
    </div>
);

This is how I have tried it, but cant seem to get it to work. I get an error Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object

Is pushing the component to the array an issue then trying to render the array? Not quite sure where to go from here. Thanks!

Chipe
  • 4,641
  • 10
  • 36
  • 64

2 Answers2

1

The main reason your code doesn't work is that you're creating an array of React elements and treating them as an array of React components. When you do

<div key={index}>
    <NewImagePlacement />
</div>

React expects NewImagePlacement to be a React component (usually a class or a string like "div" or "input". However, the contents of the array are created React elements, from where you did componentToUse (which would be better named elementToUse. Basically, a component plus props gives you an element:

const myElement = <Component prop="my-prop" />;

So you should instead do this:

<div key={index}>
    { NewImagePlacement }
</div>

to include the element in your render.

P.S. Using array index as a key is an antipattern if the array can re-order - see this bit of React documentation (https://facebook.github.io/react/docs/lists-and-keys.html)

P.P.S Your use of Array.map() is very weird - usually the point of doing a map() is to create a new array, but you don't do that. Maybe use a .forEach() instead to avoid confusion!

Duncan Thacker
  • 5,073
  • 1
  • 10
  • 20
-1

If you have array with objects that have position property, just sort array by that property and then map to your components

images = [{
  img: image1,
  placementIndex: 2
 },
 {
  img: image2,
  placementIndex: 0
  },
{
img: image3,
placementIndex: 1
}]

mages.sort((a,b) => a.placementIndex - b.placementIndex)
     .map(a=><ImageComponent ...a />)

If you want to do shuffle check How can I shuffle an array? for algorithms to do it.

So you will end up with

imageComponents.shuffle(); // see linked question for implementation

If you want not to shuffle but shift them as a "ring" just do shift and concat

function shift_ring(components, n) {
  n = n % components.length
  return components.slice(n).concat(a.slice(0,n-1))
}

shift_ring(imageComponents, 3)
vittore
  • 17,449
  • 6
  • 44
  • 82