reactjstypescriptstatezustand

update zustand store in onChange event create input delay


I have a input delay issue when I try to set the state of a zustand variable in onChange event.

const BuildOrder = (props: { setOpen: Function }) => {
  const { almacenes, isLoadingAlmacenes } = useGetAlmacenes();
  const { articlesRes, isLoadingArticles } = useGetArticlesBySearch();
  const {
    warehouseSelected,
    setWarehouseSelected,
    setArticles,
    articles,
    setArticlesFetched,
    articlesFetched,
    setSearch,
  } = useDirectlyPurchaseRequestOrderStore(
    (state) => ({
      warehouseSelected: state.warehouseSelected,
      setWarehouseSelected: state.setWarehouseSelected,
      setArticles: state.setArticles,
      articles: state.articles,
      setArticlesFetched: state.setArticlesFetched,
      articlesFetched: state.articlesFetched,
      setSearch: state.setSearch,
    }),
    shallow
  );
  const [articleSelected, setArticleSelected] = useState<Article | null>(null);
  const [amountText, setAmountText] = useState('');
  const [warehouseError, setWarehouseError] = useState(false);
  const [articleError, setArticleError] = useState(false);`your text`
  const [amountError, setAmountError] = useState(false);

  if (isLoadingAlmacenes)
    return (
      <Box sx={{ display: 'flex', flex: 1, justifyContent: 'center', p: 6 }}>
        <CircularProgress size={40} />
      </Box>
    );
  return (
    <Stack sx={{ display: 'flex', flex: 1, mt: 2 }}>
      <Stack sx={{ display: 'flex', flex: 1, maxWidth: 300 }}>
        <Typography sx={{ fontWeight: 500, fontSize: 14 }}>Seleccionar almacén</Typography>

        <TextField
          select
          label="Almacén"
          size="small"
          error={warehouseError}
          helperText={warehouseError && 'Selecciona un almacén'}
          value={warehouseSelected}
          onChange={(e) => {
            setWarehouseError(false);
            setWarehouseSelected(e.target.value);
          }}
        >
          {almacenes.map((warehouse) => (
            <MenuItem key={warehouse.id} value={warehouse.id}>
              {warehouse.nombre}
            </MenuItem>
          ))}
        </TextField>
      </Stack>
      <Divider sx={{ my: 2 }} />
      <Box
        sx={{
          display: 'flex',
          flex: 1,
          justifyContent: 'space-between',
          columnGap: 2,
          flexDirection: { xs: 'column', sm: 'row' },
          rowGap: { xs: 2, sm: 0 },
        }}
      >
        <Stack sx={{ display: 'flex', flex: 1 }}>
          <Typography sx={{ fontWeight: 500, fontSize: 14 }}>Seleccionar articulo</Typography>
          <Autocomplete
            disablePortal
            fullWidth
            filterOptions={filterArticleOptions}
            onChange={(e, val) => {
              e.stopPropagation();
              setArticleSelected(val);
              setArticleError(false);
            }}
            loading={isLoadingArticles && articlesFetched.length === 0}
            getOptionLabel={(option) => option.nombre}
            options={articlesFetched}
            value={articleSelected}
            noOptionsText="No se encontraron artículos"
            renderInput={(params) => (
              <TextField
                {...params}
                error={articleError}
                helperText={articleError && 'Selecciona un articulo'}
                placeholder="Artículos"
                sx={{ width: '50%' }}
                onChange={(e) => {
                  setSearch(e.target.value);
                }}
              />
            )}
          />
        </Stack>

In this Autocomplete I render dynamically my articles, I render an input TextField to controll the search state to render a few items, when I write in my TextField thats update my value store in onChange event but thats create a input delay on the textField and looks so laggy.


export const useGetArticlesBySearch = () => {
  const [isLoadingArticles, setIsLoadingArticles] = useState(true);
  const [articlesRes, setArticles] = useState<Article[]>([]);
  const search = useDirectlyPurchaseRequestOrderStore(useShallow((state) => state.search));

  useEffect(() => {
    const fetchData = async () => {
      setIsLoadingArticles(true);
      try {
        const res = await getArticlesBySearch(search);
        setArticles(res);
      } catch (error) {
        console.log(error);
      } finally {
        setIsLoadingArticles(false);
      }
    };
    fetchData();
  }, [search]);
  return { isLoadingArticles, articlesRes };
};

I call the state value of my store here an search the articles.

I solved the issue creating a useState and prop to my custom hook but I want to know, is there another way to do only with zustand?

I tried to know is there a way to state a zustand store variable and avoid input delay on textfield.


Solution

  • I have seen some examples where instead of destructing all the state in the same line, they would separate each item per line:

    const warehouseSelected = useDirectlyPurchaseRequestOrderStore((state) => state.warehouseSelected)
    const setWarehouseSelected = useDirectlyPurchaseRequestOrderStore((state) => state.setWarehouseSelected) 
    ...rest of the items
    

    I would try this to see if it improves performance