Использование хука useMemo () в React приводит к тому, что моя функция отстает - PullRequest
0 голосов
/ 11 апреля 2019

Я использую ловушку возврата useMemo и фильтрую массив элементов. Затем у меня есть функция переключения, которая переключает, является ли элемент истинным или ложным, а затем отправляет этот элемент обратно в API, если он является истинным или ложным, и добавляет его в список. Внутри функции, которая использует хук useReducer, массив находится на один шаг позади. Например, возвращается массив элементов, и вы переключаете, продаются ли они в продаже или нет, а если вы переключаете true, они добавляются в saleList, а если они переключаются в не для продажи, они добавляются в notSaleList. В функции длина saleList вернется к 3, но на самом деле это 4, затем вы удаляете дом, чтобы сделать его 3, но он вернет 4. Кто-нибудь знает, почему это было бы спасибо?

const homesReducer = (state, action) => {
  switch (action.type) {
    case 'FETCH_INIT':
      return {
        ...state,
        isLoading: true,
        isError: false,
      };
    case 'FETCH_SUCCESS':
      //action.payload to object
      const entities = action.payload.reduce((prev, next) => {
        return { ...prev, [next.Id]: next };
      }, {});
      return {
        ...state,
        isLoading: false,
        isError: false,
        homes: entities,
      };
    case 'FETCH_FAILURE':
      return {
        ...state,
        isLoading: false,
        isError: true,
      };
    case 'TOGGLE_SALE_HOME_INIT':
      return {
        ...state,
        homes: {
          ...state.homes,
          // ask Jenkins
          [action.payload]: {
            ...state.homes[action.payload],
            IsSaleHome: !state.homes[action.payload].IsSaleHome,
          },
        },
      };
    case 'TOGGLE_SALE_HOME_SUCCESS':
      return {
        ...state,
      };
    case 'TOGGLE_SALE_HOME_FAILURE':
      // TODO update back if failed
      return {
        ...state,
        homes: {
          ...state.homes,
          // ask Jenkins
          [action.payload]: {
            ...state.homes[action.payload],
            IsSaleHome: !state.homes[action.payload].IsSaleHome,
          },
        },
      };  
    default:
      return { ...state };
  }
};

const useOnDisplayApi = activeLotNumber => {
    const [state, dispatch] = useReducer(homesReducer, {
      isLoading: false,
      isError: false,
      homes: [],
      saleHomes: [],
     });

     const homes = useMemo(() => {
       return Object.keys(state.homes).map(id => {
       return state.homes[id];
     });
      }, [state.homes]);
     }

     const saleHomes = useMemo(() => {
       return homes.filter(home => {
       return home.IsSaleHome;
     });
     }, [homes]);

     const notSaleHomes = useMemo(() => {
       return homes.filter(home => {
       return !home.IsSaleHome && !home.IsSuggestedSaleHome;
      });
     }, [homes]);

    const toggleSaleHome = async (home, undo = true) => {
    dispatch({ type: 'TOGGLE_SALE_HOME_INIT', payload: home.Id });
    try {
      const didUpdate = await updateInventory(
        activeLotNumber,
        home.InventoryId,
        {
          InventoryId: home.InventoryId,
          IsSaleHome: !home.IsSaleHome,
        }
      );
      if (didUpdate == true) {
        dispatch({ type: 'TOGGLE_SALE_HOME_SUCCESS' });
      } 
      else {
          dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE', payload: home.Id });
      }
    } catch (error) {
      setTimeout(() => {
        dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE' });
      }, 600);
    }
  };

Ответы [ 2 ]

0 голосов
/ 15 апреля 2019

Я решил проблему, добавив оператор if перед INIT.

const toggleSaleHome = async (home, undo = true) => {
    if (saleHomes.length > 9 && !home.IsSaleHome) {
      toast.error(
        <div>
          {`${home.Name} could not be added. You already have selected 10 sale homes.`} 
        </div>,
        {
          className: 'error-toast',
          progressClassName: 'error-progress-bar',
          closeButton: false,
          position: toast.POSITION.BOTTOM_RIGHT,
        }
      );
      return;
    }
    dispatch({ type: 'TOGGLE_SALE_HOME_INIT', payload: home.Id });
    try {
      const didUpdate = await updateInventory(
        activeLotNumber,
        home.InventoryId,
        {
          InventoryId: home.InventoryId,
          IsSaleHome: !home.IsSaleHome,
        }
      );
      if (didUpdate == true) {
        dispatch({ type: 'TOGGLE_SALE_HOME_SUCCESS' });
      } 
      else {
          dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE', payload: home.Id });
      }
    } catch (error) {
      setTimeout(() => {
        dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE' });
      }, 600);
    }
  };

Вся моя проблема заключалась в том, что я не хотел, чтобы больше домов можно было переключать после того, как они достигли 10 и до «INIT» будет доступно реальное состояние продажи, поэтому saleHomes.length является точным.

0 голосов
/ 11 апреля 2019

Обновление после отправки не доступно сразу и является асинхронным. Таким образом, ваше приложение пройдет еще один цикл рендеринга, чтобы отразить обновление.

Вам нужно использовать useEffect для вызова API после обновления и не вызывать его при первоначальном рендеринге.

const initialRender = useRef(true);
useEffect(() => {
    if(initialRender.current) {
         initialRender.current = false;
    } else {
      try {
          const didUpdate = await updateInventory(
            activeLotNumber,
            home.InventoryId,
            {
              InventoryId: home.InventoryId,
              IsSaleHome: !home.IsSaleHome,
            }
          );
          if (didUpdate == true) {
            dispatch({ type: 'TOGGLE_SALE_HOME_SUCCESS' });
          } 
          else {
              dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE', payload: home.Id });
          }
        } catch (error) {
          setTimeout(() => {
            dispatch({ type: 'TOGGLE_SALE_HOME_FAILURE' });
          }, 600);
        }
    }

}, [home])

const toggleSaleHome = async (home, undo = true) => {
    dispatch({ type: 'TOGGLE_SALE_HOME_INIT', payload: home.Id });
}
...