1

I'm trying to render some loading elements (just empty <li>'s at this point) within a component while I wait for axios to retrieve data from my backend. To do this I'm using a ternary operator, but for some reason I'm not getting any rendering from it - no matter if the condition is evaluates to true or false.

My Code

class Content extends React.Component{
    constructor(){
        super();
        this.state = { currentItemIndex: 0 };
    }

    render(){
        // results will either be an empty array [] or an array populated with objects
        let results = this.props.results;
        return <div className="content">
            // note that this className will return the correct results using the same logic
            <div className={(results.length ? "results" : "loading")}>
                <ul>{ 
                    results.length ? 
                    // results has data so render it all out
                    results.map(data => {
                        const index = this.state.currentItemIndex + 1;
                        this.setState({ currentItemIndex: index });

                        return <Result key={data.slug} data={data} index={index} />
                    }) :
                    // results has no data so render 8 empty list elements
                    new Array(8).map(() => <li></li>)
                }</ul>
            </div>
        </div>;
    }
}

So, using the above code, whether my results array is populated or not, it will neither render the <Result /> component OR the 8 empty <li>'s like it should. Even stranger, if I change the code to something like this:

{ results.length ? "there are results" : "no results" }

It will do it just fine.

I'm fairly new to React so the problem may seem obvious, but as far as I'm aware, I'm doing everything correctly. All help is appreciated, cheers.

GROVER.
  • 4,071
  • 2
  • 19
  • 66
  • Try to inspect the elements with DevTool, my guess is its a CSS problem. For further help try making reproducible example in a sandbox. [codesandbox](https://codesandbox.io/s/vanilla-react-template-irhcq), [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) – Dennis Vash Jul 12 '20 at 18:16
  • @DennisVash Not a CSS problem, the elements don't ever appear in the DOM. – GROVER. Jul 12 '20 at 18:16
  • Also, you mutate state `++this.state.currentItemIndex`, https://stackoverflow.com/questions/37755997/why-cant-i-directly-modify-a-components-state-really – Dennis Vash Jul 12 '20 at 18:18
  • @DennisVash oh, thanks for that pickup, didn't even notice. – GROVER. Jul 12 '20 at 18:18

1 Answers1

1

A couple of things:

  1. You are calling this.setState() in the render which will result in a Maximum update depth exceeded error. I'm not sure what you are doing with the currentItemIndex, but you should move that this.setState() call to some handler outside of the render.

  2. You don't get an array with 8 elements when you do new Array(8). From the docs on Array() constructor:

If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with its length property set to that number (Note: this implies an array of arrayLength empty slots, not slots with actual undefined values)

In your case, there are no items in the array so the map returns no list items.

You can achieve this by doing:

Array.from({ length: 8 }).map((x) => {
  console.log(x);
  //you could return <li></li> in your case
});
Anthony
  • 6,422
  • 2
  • 17
  • 34
  • Thanks, this helped a lot. I ended up just using the `useState` hook to update my index and converted my `class` component to a functional component. – GROVER. Jul 13 '20 at 02:37