react-nativeasynchronousreduxredux-toolkitdispatch

Dispatching an action in redux toolkit too slow


I am creating a checklist which can have nested items too (same as in trello). After creating a checklist and adding items, though it works fine, but when i try to toggle any item (i can mark it as completed or not completed), I am dispatching an action at that time to update the global state, but it is too slow. It freezes the whole UI.

Here is the relevant code;

 dispatch(
        updatecarditem({
          checklistId,
          itemId: index,
          itemStatus: checked,
        }),
      );

 updatecarditem: (state: any, {payload}) => {
      const checklistId = payload.checklistId;
      const itemId = payload.itemId;

      let item =
        state.entities[0]?.checklist?.[checklistId]?.checklistItem?.[itemId];
      if (payload.itemTitle != undefined) item.itemTitle = payload.itemTitle;
      if (payload.itemStatus != undefined) item.itemStatus = payload.itemStatus;
    },

So here, i am simply accessing the nested item and updating the itemTitle or status accordingly. When changing the itemStatus (toggling the checkbox), it freezes the whole UI and is too slow to update, though it works but is too slow.

One thing which i can think can solve the problem is if we have async actions. So is there any way to dispatch actions asyncronously (this is a secondary question).

EDIT:

This is a rough structure of the components;

My main checklist;

export const CheckListItem: FC<CheckListItemProps> = ({item, index}) => {
  const card = useSelector<any, any>(cardDetails);

  const [value, setValue] = useState(item?.checklistTitle);
  const [newItem, setNewItem] = useState('');

  const dispatch = useDispatch();

  useEffect(() => {
    setValue(item?.checklistTitle);
  }, [item?.checklistTitle]);

  const toggleVisible = () => {
    setVisible((prev) => !prev);
  };

  const addCheckistItem = useCallback(() => {
    if (!newItem.length) {
      return;
    }
    const newCItem = {itemTitle: newItem, itemStatus: false};

    updateChecklist([...item?.checklistItem, newCItem]);
    setNewItem('');
  }, [newItem, item?.checklistItem]);

  const updateChecklist = useCallback(
    (clitem = item?.checklistItem) => {
      if (value.length < 3) {
        showToast(
          'error',
          'Checklist name should contain atleast 3 characters',
        );
        return;
      }
      let newls = [...card?.checklist];
      newls[index].checklistTitle = value;
      newls[index].checklistItem = clitem;

      dispatch(
        updatecard({
          checklist: newls,
        }),
      );
    },
    [value, card?.checklist],
  );

  return (
      <VStack style={styles.cardinfoviews}>
       
          <CustomInput
            onSubmit={updateChecklist}
            value={value}
            setValue={setValue}
          />
     
          <VStack style={styles.cardinfoviews}>
            {item?.checklistItem?.map((citem: any, itemindex: number) => (
              <CheckItem // THIS IS THE NESTED COMPONENT
                key={itemindex}
                citem={citem}
                index={itemindex}
                checklistId={index}
              />
            ))}

            <Input
              onSubmitEditing={addCheckistItem}
              value={newItem}
              onChangeText={setNewItem}
              maxLength={40}
              variant="underlined"
              placeholder="Add item..."
            />
          </VStack>
        )
      </VStack>
  );
};

Then the nested component;

const CheckItem: FC<CheckItemProps> = ({citem, index, checklistId}) => {
  const [value, setValue] = useState(citem?.itemTitle);
  const [checked, setChecked] = useState(citem?.itemStatus);

  const dispatch = useDispatch();

  useEffect(() => {
    setValue(citem?.itemTitle);
  }, [citem?.itemTitle]);

  useEffect(() => {
    setChecked(citem?.itemStatus);
  }, [citem?.itemStatus]);

  const updatecheckItem = useCallback(
    (checked = citem?.itemStatus) => {
      setChecked(checked);
      dispatch(
        updatecarditem({
          checklistId,
          itemId: index,
          itemStatus: checked,
        }),
      );
    },
    [checklistId, index],
  );

  const updateItemName = useCallback(() => {
    if (value.length < 3) {
      showToast('error', 'Item name should contain atleast 3 characters');
      return;
    }

    dispatch(
      updatecarditem({
        checklistId,
        itemId: index,
        itemTitle: value,
      }),
    );
  }, [value, index, checklistId]);


  return (
      <Checkbox
        value={citem?.itemTitle}
        isChecked={checked}
        onChange={updatecheckItem}>
          <Input
            w="85%"
            onSubmitEditing={updateItemName}
            variant="unstyled"
            value={value}
            onChangeText={setValue}
            multiline
            numberOfLines={1}
            blurOnSubmit
          />
      </Checkbox>
  );
};

EDIT Found that, it is bacause of too many re-renders. Fixing that now. If anyone can see the issues in the above code which can be causing too many re-renders, please comment down. Thanks!


Solution

  • This issue was not related to actions being dispatched but the way i was accessing the data from store (thanks to @phry), I was selecting too much of the state which caused unnecessary re-renders as the data was being changed from multiple child components. Fixed the re-rendering but still some optimisation needed in the child components.