beforesemicolon / flatlist-react

A helpful utility component to handle lists in react like a champ
MIT License
95 stars 17 forks source link

renderOnScroll causing bug #77

Closed Jaaneek closed 3 years ago

Jaaneek commented 3 years ago

FlatList Version :1.4.3

Describe the bug : Enabling renderOnScroll throws error when searchTerm doesnt match any elements Steps to reproduce the behavior : Set renderOnScroll to true search props:

search={{
            by: ["title", "message"],
            term: searchTerm,
            caseInsensitive: true,
          }}

Render around 400 elements. set searchTerm to something like "8218132873873nrui3" so that it wont match anything. set searchTerm to something that will match a few elements.

Expected behavior :after a short moment error will appear: TypeError: Cannot set property 'scrollTop' of null

Desktop (please complete the following information):

Smartphone (please complete the following information):

Screenshots image image image

ECorreia45 commented 3 years ago

Sorry for delay in noticing this. Working on a fix right away.

ECorreia45 commented 3 years ago

@Jaaneek I was not able to reproduce this, can you provide me with more details, please?

Jaaneek commented 3 years ago
import React, { useEffect, useState } from "react";
import {
  Button,
  DialogActions,
  DialogTitle,
  TextField,
  useMediaQuery,
} from "@material-ui/core";
import { Dialog, DialogContent } from "@material-ui/core";
import styles from "../SettingsPage.module.scss";
import SingleEventContainer from "../../../EventComponents/SingleEventContainer/SingleEventContainer";
import UseIcsImport from "./UseIcsImport";
import { useMutation } from "react-apollo";
import ALL_EVENTS from "../../../ApolloQueries/ALL_EVENTS";
import ADD_EVENTS from "../../../ApolloQueries/ADD_EVENTS";
import FlatList from "flatlist-react";
import Checkbox from "@material-ui/core/Checkbox";
import { FormControlLabel } from "@material-ui/core";
const IcsImportButton = () => {
  const [isOpen, setIsOpen] = useState(false);
  const isMobile = useMediaQuery("(max-width: 767px)");
  return (
    <div className={styles.buttonLeftContainer}>
      <Button
        onClick={() => setIsOpen(true)}
        variant="contained"
        color="primary"
        className={styles.buttonLeft}
      >
        Import ICS file
      </Button>
      {isOpen && (
        <IcsImportDialog
          title="Import events"
          show={isOpen}
          handleClose={() => setIsOpen(false)}
          isMobile={isMobile}
        ></IcsImportDialog>
      )}
    </div>
  );
};

const IcsImportDialog = ({ show, handleClose, isMobile, title }) => {
  const [events] = UseIcsImport();
  const [addEvents] = useMutation(ADD_EVENTS);
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedEvents, setSelectedEvents] = useState([]);
  const saveEvents = () => {
    if (!selectedEvents.some((x) => x)) {
      handleClose();
      return;
    }
    const mappedEvents = events
      .map(({ type, title, message, date, invokeDates }) => {
        return {
          title,
          message,
          invokeDates,
          date,
          eventTypeName: type,
        };
      })
      .filter((_, ind) => selectedEvents[ind]);
    addEvents({
      variables: { events: mappedEvents },
      refetchQueries: [{ query: ALL_EVENTS }],
    });
    handleClose();
  };
  useEffect(() => {
    const transformedEvents = events.map(() => false);
    setSelectedEvents(transformedEvents);
  }, [events]);

  const renderEvent = (event, index) => {
    return (
      <SingleEventContainer
        key={String(event.date) + String(event.title)}
        checked={!!selectedEvents[index]}
        onCheckboxChange={(checkValue) => {
          const newselectedEvents = selectedEvents.map((val, valIndex) => {
            if (valIndex === index) {
              return checkValue;
            }
            return val;
          });
          setSelectedEvents(newselectedEvents);
        }}
        {...event}
      ></SingleEventContainer>
    );
  };

  return (
    <Dialog
      scroll="paper"
      open={show}
      onClose={handleClose}
      fullScreen={isMobile}
      fullWidth
    >
      <DialogTitle className={styles.icsModalTitle}>
        <TextField
          fullWidth
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
          placeholder="Seach events by title or message"
        ></TextField>
        <FormControlLabel
          className={styles.allEventsCheckbox}
          control={
            <Checkbox
              onChange={({ target: { checked: checkValue } }) => {
                setSelectedEvents(selectedEvents.map(() => checkValue));
              }}
              color="primary"
              name="Select all events checkbox"
            ></Checkbox>
          }
          labelPlacement="start"
          label="Select All"
        ></FormControlLabel>
      </DialogTitle>
      <DialogContent dividers className={styles.contentContainer}>
        <FlatList
          search={{
            by: ["title", "message"],
            term: searchTerm,
            caseInsensitive: true,
          }}
          list={events}
          renderItem={renderEvent}
          renderWhenEmpty={() => <div>List is empty!</div>}
          sortBy={["date"]}
          renderOnScroll
          srollToTop={false}
        />
      </DialogContent>
      <DialogActions>
        <Button variant="text" color="default" onClick={handleClose}>
          Close
        </Button>
        <Button variant="contained" color="primary" onClick={saveEvents}>
          Save Changes
        </Button>
      </DialogActions>
    </Dialog>
  );
};

export default IcsImportButton;

Error appears after some moment, the list is not empty but after providing searchTerm that doesnt match any of the elements it doesnt show anything just as supposed. It shouldnt show error because of that right?

ECorreia45 commented 3 years ago

No you are correct. Ill retests using the cocktail of options as you have them and get back to you.

ECorreia45 commented 3 years ago

Seems like this issue was fixed in this commit:

https://github.com/ecorreiadev/flatlist-react/commit/0acaa816c343da56578a2e2f209d1f686bb6e82c

in release 1.5.0

I will keep this issue opened until the next release and let you know about it.

Thank you

[details of the bug] This is happening because in between the next browser paint and the list update(on search) the list is no longer rendered (due to no match) then when the code executes on the paint after there is no element to assign the scrollTop to (as the error says)