Search code examples
javascriptreactjsstatesetstate

this.setState deletes filter - ReactJS


Okey guys so i have quite an issue here . I'm countering this problem since few days so i will be glad if someone can give me a hint how can i fix it . ( or someone can propouse a solution ) . So i have managed to create my own table via material-table library . But in my case i need to have the docID and the docNR as a value from each checkbox . And that's why i have used a separate component from material-ui - <Checkbox/> . In conclusion i have tracked that my issue is coming from my handleCheckBox function . And specifically from my update state function this.setState . Is my problem coming from there that my setState function is Asynchronous ? Or am i doing something wrong you will say .

Visual example enter image description here

My method

handleCheckboxClick = (clickedItem) => {

        let newDocList = { ...this.state.docList };
        if (clickedItem.checked) {
            newDocList[clickedItem.documentId] = clickedItem.documentNumber;
        } else {
            delete newDocList[clickedItem.documentId];
        }

        let toSee = Object.keys(newDocList).length > 0 ? true : false;

        this.setState({
                docList: newDocList,
                visible: toSee
            }, () => {
                console.log()
            });

        const updatedArray = this.state.items.map((item) => {
            item.checked = item.documentId === clickedItem.documentId ? !item.checked : item.checked;
            return item;
        });

        this.setState({

            items: updatedArray,
        });
    };

P.S.

I have tried an empty function with only a console init and it is working like a charm .


Solution

  • The issue here is that upon checking the box your table gets re-rendered which is making it re-create the columns array. This array is used to store the filtering data.

    What you'll need to do is store the columns data somewhere outside the render function. For a simple example look at useState (or consider redux/mobx):

    
    const BasicFilteringWithState = () => {
      const [columnsData] = useState([
        { title: "Name", field: "name" },
        { title: "Surname", field: "surname" },
        { title: "Birth Year", field: "birthYear", type: "numeric" },
        {
          title: "Birth Place",
          field: "birthCity",
          lookup: { 34: "İstanbul", 63: "Şanlıurfa" }
        }
      ]);
    
      return (
        <MaterialTable
          title="Basic Filtering Preview"
          columns={columnsData}
          data={[
            { name: "Mehmet", surname: "Baran", birthYear: 1987, birthCity: 63 },
            {
              name: "Zerya Betül",
              surname: "Baran",
              birthYear: 2017,
              birthCity: 34
            }
          ]}
          options={{
            filtering: true
          }}
        />
      );
    };
    
    

    Look at this sandbox: https://codesandbox.io/s/laughing-einstein-1ig9m

    I left the sample as is and added the one with useState. you can filter both tables and then click the test button at the bottom. You'll see the difference.

    In a related note, don't forget to check why your table gets re-rendered because of the checkbox. That might be a sign your components aren't optimized (memoized)...