如何解决如何从反冲的atomFamily中获取所有元素?
我是第一次玩反冲,无法弄清楚我如何从atomFamily中读取所有元素。假设我有一个应用程序,用户可以在其中添加餐点:
export const meals = atomFamily({
key: "meals",default: {}
});
我可以按以下步骤初始化餐点:
const [meal,setMeal] = useRecoilState(meals("bananas"));
const bananas = setMeal({name: "bananas",price: 5});
我如何阅读已添加到此atomFamily的所有项目?
解决方法
您必须跟踪atomFamily
的所有ID,才能获得家庭的所有成员。
请记住,这实际上不是列表,更像是地图。
这样的事情应该会让你前进。
// atomFamily
const meals = atomFamily({
key: "meals",default: {}
});
const mealIds = atom({
key: "mealsIds",default: []
});
在族内创建新对象时,还必须更新mealIds
原子。
我通常使用useRecoilCallback
钩子将它们同步在一起
const createMeal = useRecoilCallback(({ set }) => (mealId,price) => {
set(mealIds,currVal => [...currVal,mealId]);
set(meals(mealId),{name: mealId,price});
},[]);
通过这种方式,您可以通过以下方式制作餐点:
createMeal("bananas",5);
并通过以下方式获取所有ID:
const ids = useRecoilValue(mealIds);
,
除了使用useRecoilCallback之外,还可以将它与选择器系列一起使用。
api.getToken(URL,userData).then((result) => {
// if user is logged in successfully call the action
if (result) this.$store.dispatch('auth/updateAccessToken');
})
此外,如果您想支持重置,可以使用以下代码:
// atomFamily
const mealsAtom = atomFamily({
key: "meals",default: []
});
// abstraction
const meals = selectorFamily({
key: "meals-access",get: (id) => ({ get }) => {
const atom = get(mealsAtom(id));
return atom;
},set: (id) => ({set},meal) => {
set(mealsAtom(id),meal);
set(mealIds (id),prev => [...prev,meal.id)]);
}
});
如果您使用的是Typescript,则可以使用以下guard使它更加优美。
// atomFamily
const mealsAtom = atomFamily({
key: "meals",set: (id) => ({set,reset},meal) => {
if(meal instanceof DefaultValue) {
// DefaultValue means reset context
reset(mealsAtom(id));
reset(mealIds (id));
return;
}
set(mealsAtom(id),meal.id)]);
}
});
使用带有Typescript的后卫看起来像:
import { DefaultValue } from 'recoil';
export const guardRecoilDefaultValue = (
candidate: unknown
): candidate is DefaultValue => {
if (candidate instanceof DefaultValue) return true;
return false;
};
,
以下是我在当前项目中使用它的方式:
(对于上下文,这是从字段选项对象数组创建的动态表单。表单值通过 graphql 突变提交,因此我们只需要进行最少的更改。因此,表单是在用户编辑时构建的字段)
import { atom,atomFamily,DefaultValue,selectorFamily } from 'recoil';
type PossibleFormValue = string | null | undefined;
export const fieldStateAtom = atomFamily<PossibleFormValue,string>({
key: 'fieldState',default: undefined,});
export const fieldIdsAtom = atom<string[]>({
key: 'fieldIds',default: [],});
export const fieldStateSelector = selectorFamily<PossibleFormValue,string>({
key: 'fieldStateSelector',get: (fieldId) => ({ get }) => get(fieldStateAtom(fieldId)),set: (fieldId) => ({ set,get },fieldValue) => {
set(fieldStateAtom(fieldId),fieldValue);
const fieldIds = get(fieldIdsAtom);
if (!fieldIds.includes(fieldId)) {
set(fieldIdsAtom,(prev) => [...prev,fieldId]);
}
},});
export const formStateSelector = selectorFamily<
Record<string,PossibleFormValue>,string[]
>({
key: 'formStateSelector',get: (fieldIds) => ({ get }) => {
return fieldIds.reduce<Record<string,PossibleFormValue>>(
(result,fieldId) => {
const fieldValue = get(fieldStateAtom(fieldId));
return {
...result,[fieldId]: fieldValue,};
},{},);
},set: (fieldIds) => ({ get,set,reset },newValue) => {
if (newValue instanceof DefaultValue) {
reset(fieldIdsAtom);
const fieldIds = get(fieldIdsAtom);
fieldIds.forEach((fieldId) => reset(fieldStateAtom(fieldId)));
} else {
set(fieldIdsAtom,Object.keys(newValue));
fieldIds.forEach((fieldId) => {
set(fieldStateAtom(fieldId),newValue[fieldId]);
});
}
},});
原子是选择器在应用中的 3 个地方使用:
在字段组件中:
...
const localValue = useRecoilValue(fieldStateAtom(fieldId));
const setFieldValue = useSetRecoilState(fieldStateSelector(fieldId));
...
在保存处理组件中(尽管在带有显式提交按钮的表单中这可能更简单):
...
const fieldIds = useRecoilValue(fieldIdsAtom);
const formState = useRecoilValue(formStateSelector(fieldIds));
...
在另一个处理表单操作的组件中,包括表单重置:
...
const resetFormState = useResetRecoilState(formStateSelector([]));
...
const handleDiscard = React.useCallback(() => {
...
resetFormState();
...
},[...,resetFormState]);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。