Search code examples
javascriptreactjspapaparse

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>
)

Solution

  • 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..