skip to Main Content
const MyComponent = () => {
  const [avaliador, setAvaliador] = useState("");
  const [avaliadoresList, setAvaliadoresList] = useState([]);
  const [DataResultsTotal, setDataResultsTotal] = useState([]);

  const filters = useSelector((state) => state.filter);

  // not all consts is here, only to show the problem

  const fetchData = async (token) => {
    try {
      const responseResult = await axios.get(
        "http://apicall/example/all",
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );

      setDataResultsTotal(responseResult.data);
      setAreaProgs(responseResult.data.length);

      // and continuous some calc to send to updates the state and show to the user
      });
      setError(responseResult.data.erro);
    } catch (error) {
      console.error("something wrong", erro);
    }
  };

  useEffect(() => {
    setToken(localStorage.getItem("token"));
    fetchData(token);
  }, [token]);

  const handleChangeSelect = (event) => {
    setAvaliador(event.target.value);
    dispatch(updateFilters({ ["name"]: event.target.value }));
  };

  const shouldDisplay = (lev) => {
    let matchesSearchText = lev.noEncarregado
      .toUpperCase()
      .includes(filters.noEncarregado);

    // let matchesCategory = lev.id.toLowerCase().includes(filters.ids);
    //  filters.ids.length > 0
    //   ? filters.ids.some((id) => id == lev.category)
    //    : true;
    return matchesSearchText;
  };

  const filteredData = DataResultsTotal.filter((lev) => shouldDisplay(lev));
  setDataResultsTotal(filteredData); // the error goes here

  return (
    <Box
      paddingLeft={isOpen ? "80px" : "200px"}
      bgcolor={`${colors.slate[100]}`}
    >
      <Grid container>
        <Grid item xs={12} sm={6} md={6} lg={6}>
          <Box>
            <Typography
              variant="h4"
              sx={{
                fontWeight: "bold",
                marginLeft: "20px",
                marginTop: "20px",
              }}
            >
              text title
            </Typography>
            <Typography
              variant="h6"
              sx={{
                marginLeft: "20px",
                marginTop: "5px",
                marginBottom: "20px",
              }}
            >
              anotr text
            </Typography>
          </Box>
        </Grid>
        <Grid
          item
          xs={12}
          sm={6}
          md={6}
          lg={6}
          marginTop={"20px"}
          marginBottom={"10px"}
        >
          <Box
            display={"flex"}
            alignItems={"center"}
            height={"100%"}
            justifyContent={"flex-end"}
          >
            <DownloadBtn DownText={true} />
          </Box>
        </Grid>
        <Grid item xs={12} sm={6} md={3} lg={3}>
          <Box sx={{ mx: "10px", my: "5px" }}>
            <Box sx={{ minWidth: 150 }}>
              <FormControl fullWidth>
                <InputLabel id="demo-simple-select-label">
                  texttt
                </InputLabel>
                <Select
                  labelId="demo-simple-select-label"
                  id="demo-simple-select"
                  value={avaliador}
                  label="Avaliador"
                  onChange={handleChangeSelect}
                >
                  {avaliadoresList.map((avaliador) => (
                    <MenuItem key={avaliador} value={avaliador}>
                      {avaliador}
                    </MenuItem>
                  ))}
                </Select>
              </FormControl>
            </Box>
          </Box>
        </Grid>

        <Grid item xs={6} sm={6} md={3} lg={3}>
          <Box sx={{ mx: "10px", my: "5px" }}>
            <CardHome
              size="h7"
              sizedesc="h3"
              name="text"
              icon={
                <ListAltOutlinedIcon
                  sx={{
                    fontSize: "28px",
                    color: `${colors.greenAccent[800]}`,
                  }}
                />
              }
              description={<Counter from={0} to={showfiltereddata} />}
            />
          </Box>
        </Grid>
      </Grid>
    </Box>
  );
}

Well, I’m trying to filter something with a select with Material-UI and Redux, everything is ok with the filter, but I’m not getting how I recalculated the filtered data and show to the user.

In this code, I will get the state from Redux, bring to the page, compare with the calculated data that’s becoming from API call, and save it on a const, but I need to recalculated this filtered data again, but when I try to do that, throws "too many re renders", and I know that why happens, but I don’t know the better approach to deal with it, maybe two useEffects?

4

Answers


  1. Do not keep the token in state.

      useEffect(() => {
        const token = localStorage.getItem("token");
        fetchData(token);
      }, []);
    

    You shouldn’t update state in an effect, especially if the state is a dependency of that effect.

    Login or Signup to reply.
  2. useEffect(() => {
        setToken(localStorage.getItem("token"));
        fetchData(token);
      }, [token]);
    

    this is causing this error to occur, i think what you should do is,

    useEffect(() => {
        localStorage.setItem('token', token);
        fetchData(token);
      }, [token]);
    
    useEffect(() => {
        setToken(localStorage.getItem("token"));
    }, []);
    

    this is also not perfect solution but as i dont know your full use context i can only provide this as solution that might work!

    Login or Signup to reply.
  3. I agree with the second half of your statement, but can you explain why state shouldn’t be updated inside useEffect()?

    To answer Codebling‘s question and your’s too I suppose, let’s analyze your code.

    useEffect(() => {
      setToken(localStorage.getItem("token"));
      fetchData(token);
    }, [token]);
    

    The behavior of the code above is that on initial render, the subroutine in the useEffect runs, setToken then mutates token and token is a dependency of the useEffect so the useEffect will run again and again and… what you have created is an infinite loop.

    Login or Signup to reply.
  4. You have an unintentional side effect.

    const filteredData = DataResultsTotal.filter((lev) => shouldDisplay(lev));
    setDataResultsTotal(filteredData); // <-- unconditional state update!
    

    filteredData is a new array reference each time the component renders, and each time a state update is enqueued and triggers a component rerender.

    Just compute and use directly the derived filteredData value, don’t use it to update the source of truth, e.g. the filters and DataResultsTotal state. Remove the unintentional side-effect setDataResultsTotal(filteredData); from the code.

    Example:

    const shouldDisplay = (lev) => lev.noEncarregado
      .toUpperCase()
      .includes(filters.noEncarregado);
    
    const filteredData = DataResultsTotal.filter(shouldDisplay);
    

    or

    const filteredData = React.useMemo(() => {
      const shouldDisplay = (lev) => lev.noEncarregado
        .toUpperCase()
        .includes(filters.noEncarregado);
    
      return DataResultsTotal.filter(shouldDisplay);
    }, [DataResultsTotal, filters]);
    

    Render the UI from the computed filteredData value instead of the DataResultsTotal state now.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search