在 React 中使用 useMemo() 钩子会导致我的函数落后一步



我正在使用useMemo钩子返回并过滤项目数组。然后,我有一个切换函数,可以切换一个项目是真还是假,然后将该项目发布回 API(如果它是真还是假(并将其添加到列表中。在使用 useReducer 钩子的函数中,数组落后一步。例如,返回项目数组,您切换它们是否在销售中,如果您切换 true,它们将被添加到销售列表中,如果它们被切换为不销售,它们将被添加到 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);
    }
  };

调度后的更新不会立即可用,并且是异步的。因此,你的应用将经历另一个呈现周期来反映更新。

您需要使用 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 });
}

我最终通过在"INIT"之前添加 if 语句来解决我的问题。

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 的实际状态可用,因此 saleHomes.length 是准确的。

相关内容

  • 没有找到相关文章

最新更新