Home > Net >  React how to render only parts of an array?
React how to render only parts of an array?

Time:02-21

I am still a bit new to react and how it works. I have a projects.js file with a list of objects that look like this:

id: 0,
    name: "Placeholder Project 1",
    description: "Project description",
    image: "./assets/images/placeholder-01.png"

There are 6 objects in this array. I am trying to render only 3 project objects at a time, and then include a button that will "load more" projects later. However, I am having trouble with just the rendering part. My component looks like this:

import React, { Component } from "react";
import NavTab from "./NavTab";
import { Card } from "react-bootstrap";
import { PROJECTS } from "../shared/projects";

function RenderProject({projects, projectsDisplayArray}) {
    const tempArray = projectsDisplayArray;
    return( 
        <div className="row">
            {                 
                projects.map(project => {
                    tempArray.indexOf(project) > -1 ? console.log('in array already') : tempArray.push(project) 
                    console.log(tempArray.length)
                    if (tempArray.length >= 3){
                        console.log('in the if')
                        return (
                            <Card key={project.id}>
                                <Card.Img variant="top" src={project.image} />
                                <Card.Body>
                                    <Card.Title>{project.name}</Card.Title>
                                    <Card.Text>
                                        {project.description}
                                    </Card.Text>
                                    
                                </Card.Body>
                                <button className="btn align-self-center">Go somewhere</button>
                            </Card>

                        )
                    }
                    else {
                        return(<div>Else return div</div>)
                    }
                })
            }
        </div>
    )
}

export default class Projects extends Component {
    
    constructor(props){
        super(props);
        this.state = {
            projectsPerScreen: 3,
            currentPage: 0,
            projects: PROJECTS,
            projectsDisplayArray: []
        }
    }
    modifyProjectsDisplayArray = props => {
        this.setState({projectsDisplayArray: [...this.state.projectsDisplayArray, props]})
    }
    render() {
        let i = 0;
        return(
            <React.Fragment>
                <NavTab/>
                <div className="projects">
                    <div className="container">
                        <button type="button" className="btn">Click</button>
                        <h1>Projects: </h1>
                        <RenderProject projects={this.state.projects} projectsDisplayArray={this.state.projectsDisplayArray} />
                        <button type="button" className="btn" onClick={() => console.log(this.state.projectsDisplayArray)}>console log</button>
                    </div>
                </div>
            </React.Fragment>
        )
    
    }
}

I am very confused on how the return method for RenderProject is working. When I begin the mapping process, I want to add each project to an array so I can keep track of how many and what projects are being rendered. When the array length hits three, I want it to stop rendering. But whenever I do this, my line if (tempArray.length <= 3) behaves in a way I don't expect it to. With how it is now, it won't return the <Card> and will instead return the else <div> for all 6 objects. But if I change the if statement to be if (tempArray.length >= 3) it will render all 6 objects inside of the array and no else <div>s. What should I be doing instead?

CodePudding user response:

I would try something like that, using the index parameter (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). For sake of simplicity I will only add the part with the mapping function.

        <div className="row">
            {                 
                projects.map((project, index) => {
                    if (index < 3){
                        return (
                            <Card key={project.id}>
                                <Card.Img variant="top" src={project.image} />
                                <Card.Body>
                                    <Card.Title>{project.name}</Card.Title>
                                    <Card.Text>
                                        {project.description}
                                    </Card.Text>
                                    
                                </Card.Body>
                                <button className="btn align-self-center">Go somewhere</button>
                            </Card>
                        )
                    }
                    else {
                        return (<div>Else return div</div>);
                    }
                })
            }
        </div>

I would however consider using filter (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) or anyway create a subarray with the needed elements, then map over that array.

CodePudding user response:

You can use state to keep track of how many array items to render by keeping track of the index you want to slice your array at. Then use a new sliced array to map over. Then you can have a button that increases the index state by 3 every time it is clicked:

import { useState } from 'react';

const Component = () => {
  const [index, setIndex] = useState(3)

  const yourArray = [...]
  const itemsToRender = yourArray.slice(0, index);

  return (
    <>
      <button onClick={() => setIndex(index   3)}>load more</button>
      <ul>
        { itemsToRender.map((item) => <li>{item}</li>) }
      </ul>
    </>
  );
}

CodePudding user response:

The important thing to remember with React is that you don't add things to the DOM in the traditional way - you update state. So, in this contrived example, I've added some data to state, and I also have a count state too.

count is initially set to 1 and on the first render the getItems function returns a new array of three items which you can then map over to get your JSX.

When you click the button it calls handleClick which sets a new count state. A new render happens, and a new set of count * 3 data is returned (six items).

And so on. I also added a condition that when the count is greater than the number of items in your data the button gets disabled.

const { useState } = React;

// So here I'm just passing in some data
function Example({ data }) {

  // Initialise the items state (from the data passed
  // in as a prop - in this example), and a count state
  const [ items, setItems ] = useState(data);
  const [ count, setCount] = useState(1);

  // Returns a new array of items determined by the count state
  function getItems() {
    return [ ...items.slice(0, count * 3)];
  }

  // Sets a new count state when the button is clicked
  function handleClick() {
    setCount(count   1);
  }

  // Determines whether to disable the button
  function isDisabled() {
    return count * 3 >= items.length;
  }

  return (
    <div>
      {getItems().map(item => {
        return <div>{item}</div>;
      })}
      <button
        onClick={handleClick}
        disabled={isDisabled()}
      >Load more
      </button>
    </div>
  );
};

// Our data. It gets passed into the component
// as a property which then gets loaded into state
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

ReactDOM.render(
  <Example data={data} />,
  document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

  • Related