bruh
bruh

Reputation: 2305

React filter large dataset without re-render (Too many re-renders error)

I have a really large array of objects, parsed (PapaParse) from a CSV:

import { readRemoteFile } from 'react-papaparse'    

const [studentData, setStudentData] = useState(null)
const [filteredStudents, setFilteredStudents] = useState([])
const [loading, setLoading] = useState(true)   

useEffect(() => { 
  grabData()
}, [])    

const grabData = () => {
  readRemoteFile('my-data.csv', {
    complete: (results) => { // this method gets called once file is finished parsing
      setStudentData(results.data)
      setLoading(false)
    }
  }
}

I want to filter the student data and only show students with the name 'Amber' for example:

const getFilteredStudents = (name) => {
  let updatedStudents = studentData.filter((student) => {
    return student.name === name
  }
  setFilteredStudents(updatedStudents)
  // Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
}

if (!loading) {
  getFilteredStudents('Amber')
}

In the above codeblock, called setFilteredStudents(updatedStudents) causes a react error.

Finally I just want to render only the filtered students in the component:

render (
  <div>
  { filteredStudents ?
    filteredStudents.map((student, index) => {
      <div key={index}>
        student.name
      </div>
    } : null
  }
  </div>
)

Upvotes: 0

Views: 732

Answers (2)

bruh
bruh

Reputation: 2305

The problem was the conditional:

if (!loading) {
  getFilteredStudents('Amber')
}

Removed it and it seems to be working. Now I just need a much better way of rendering the data, because there are about 5000 Amber objects

Upvotes: 0

sasal
sasal

Reputation: 201

This is happening because your are calling

if (!loading) {
  getFilteredStudents('Amber')
}

everytime the component renders, which triggers a new => getFilteredStudents which does => setFilteredStudents resulting into a new re-render and an infinite loop

you should instead do

const grabData = () => {
  readRemoteFile('my-data.csv', {
    complete: (results) => { // this method gets called once file is finished parsing
      setStudentData(results.data);
    }
  }
}

and just call getFilteredStudents('Amber') with a button..

Upvotes: 3

Related Questions