微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从反冲的atomFamily中获取所有元素?

如何解决如何从反冲的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 举报,一经查实,本站将立刻删除。