我正在使用useMemo挂钩返回并过滤项目数组。然后,我有了一个切换功能,该功能可以切换一个项目是true还是false,然后将该项目发布到API(如果是true或false)并将其添加到列表中。在使用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);
}
};
答案 0 :(得分:0)
分派后的更新无法立即使用,并且是异步的。因此,您的应用将经历另一个渲染周期以反映更新。
您需要在更新后使用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 });
}
答案 1 :(得分:0)
我最终通过在“ 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.length就是准确的。