Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React 1000 checkboxes - clicking/re-render takes several seconds

So I am trying to learn React, and have a quite simple application I am trying to build.

So I have a backend API returning a list of say 1000 items, each item has a name and a code. I want to put out all the names of this list into check boxes. And then do X with all selected items - say print the name, with a selectable font to a pdf document.

With this I also want some easy features like "select all" and "deselect all".

So since I am trying to learn react I am investigating a few different options how to do this. None seems good.

So I tried making a child component for each checkbox, felt clean and "react". This seems to be really bad performance, like take 2-3 seconds for each onChange callback so I skipped that.

I tried making a Set in the class with excluded ones. This too seems to be really slow, and a bad solution since things like "select all" and "deselect all" will be really ugly to implement. Like looping through the original list and adding all of them to the excluded set.

Another solution I didn't get working is modifying the original data array. Like making the data model include a checked boolean to get a default value, and then modify that. But then the data needs to be a map instead of an array. But I have a feeling this solution will be really slow too whenever clicking the checkbox. I dont quite understand why it is so slow to just do a simple checkbox.

So please tell me how to approach this problem in react.

A few direction questions:

How do I modify an array when I fetch it, say add a checked: true variable to each item in the array?

async componentDidMount() {
    const url = "randombackendapi";
    const response = await fetch(url);
    const data = await response.json();
    this.setState({ data: data.data, loading: false });
  }

Why is this so extremely slow? (Like take 3 seconds each click and give me a [Violation] 'click' handler took 3547ms) warning. And my version of each item being a sub function with callback being equally slow. How can I make this faster? - Edit this is the only question that remains.

    {this.state.data.map((item, key) => (
      <FormControlLabel
        key={item.code}
        label={item.name}
        control={
          <Checkbox
            onChange={this.handleChange.bind(this, item.code)}
            checked={!this.state.excludedSets.has(item.code)}
            code={item.code}
          />
        }
      />
    ))}

  handleChange = (code, event) => {
    this.setState({
      excludedSets: event.target.checked
        ? this.state.excludedSets.delete(code)
        : this.state.excludedSets.add(code)
    });
  };

I guess I don't understand how to design my react components in a good way.

like image 423
nesohc Avatar asked Sep 02 '25 10:09

nesohc


2 Answers

How do I modify an array when I fetch it, say add a checked: true variable to each item in the array?

Once you have the array you can use a map to add a checked key, which will just make the process much easier by utilizing map on the main array to check and an easier implementation for the select-deselect all feature

let data = [{code: 1},{code: 2},{code: 3}]

let modifiedData = data.map(item => {
return {...item, checked: false}
})
//modifiedData = [ { code: 1, checked: false }, { code: 2, checked: false }, { code: 3, checked: false } ]

I would recommend to save the modified data inside the state instead of the data you fetched since you can always modify that array to send it back to the api in the desired format

now that you have the modified array with the new checked key you can use map to select and deselect like so

const handleChange = (code) => {
  modifiedData = modifiedData.map(item => item.code === code ? {...item, checked: !item.checked}: item)
}

And as of the deselect all | select all you can use another map method to do this like so


const selectAllHandler = () => {
  modifiedData = modifiedData.map(item => {
    return {...item, checked: true}})
}

and vice-versa

const deselectAllHandler = () => {
  modifiedData = modifiedData.map(item => {
    return {...item, checked: false}})
}
like image 54
Marguel Gutierrez Avatar answered Sep 05 '25 00:09

Marguel Gutierrez


It's a common rendering issue React will have, you can use virtualize technique to reduce the amount of DOM elements to boost the re-rendering time. There're several packages you can choose, like react-virtuoso, react-window etc.

The main concept is to only render the elements inside your viewport and display others when you're scrolling.

like image 30
Leo Avatar answered Sep 05 '25 00:09

Leo