首页 > 解决方案 > 如何处理具有多种状态和动作类型的化简器和上下文

问题描述

我正在创建一个小应用程序来熟悉 React。我正在尝试遵循这篇 Kent C Dodds文章中介绍的模式。但我有比文章更多的状态。

这是我的初始状态

{
  status // the loading states of the app (pending/ resolved/ rejected)
  error // any error that occurred
  profiles // the profile list
  profile // when editing the profile selected to edit
  formType // Create or update form type
}

我已将应用程序创建到工作级别,并尝试优化我的解决方案以使其更具可扩展性。因为我在一个 reducer 中有很多动作类型。

这是我的上下文、提供者和减速器(我只添加了与异步操作相关的操作类型)

const initialState = {
  status: null,
  error: null,
  profiles: [],
  profile: null,
  formType: 'Create'
}

function profileReducer(state, action) {
  switch (action.type) {
    case 'LOADING_START': {
      return {
        ...state,
        status: 'pending',
      }
    }
    case 'LOADING_FAILED': {
      return {
        ...state,
        status: 'rejected',
        error: action.payload
      }
    }
    case 'LOADING_SUCCESS': {
      return {
        ...state,
        status: 'resolved',
      }
    }
    case 'PROFILES_GET': {
      return {
        ...state,
        profiles: action.payload,
      }
    }
   case 'FORM_TYPE_UPDATE': {
      return {
        ...state,
        formType: action.payload,
      }
    }
    case 'PROFILE_EDIT': {
      return {
        ...state,
        profile: action.payload,
      }
    }
    default: {
      throw new Error(`Unhandled action type: ${action.type}`)
    }
  }
}

function ProfileProvider({ children }) {
  const [state, dispatch] = React.useReducer(profileReducer, initialState)
  const value = [state, dispatch];
  return <ProfileContext.Provider value={value}>{children}</ProfileContext.Provider>
}

function useProfile() {
  const context = React.useContext(ProfileContext)
  if (context === undefined) {
    throw new Error('useProfile must be used within a ProfileProvider')
  }
  return context
}

async function getProfiles(dispatch) {
  dispatch({ type: 'LOADING_START' })
  try {
    const profiles = await client.getProfiles()
    dispatch({ type: 'LOADING_SUCCESS' })
    dispatch({ type: 'PROFILES_GET', payload: profiles })
  } catch (error) {
    dispatch({ type: 'LOADING_FAILED', payload: error })
    throw error;
  }
}

async function addProfile(dispatch, profile) {
  dispatch({ type: 'LOADING_START'})
  try {
    console.log({ profile });
    const addedProfile = await client.addProfile(profile)
    const profiles = await client.getProfiles()
    dispatch({ type: 'PROFILES_GET', payload: profiles })
    dispatch({ type: 'LOADING_SUCCESS' })
  } catch (error) {
    dispatch({ type: 'LOADING_FAILED', payload: error })
    throw error;
  }
}

async function updateProfile(dispatch, profile) {
  dispatch({ type: 'LOADING_START' })
  try {
    console.log({ profile });
    const updatedProfile = await client.updateProfile(profile)
    const profiles = await client.getProfiles()
    dispatch({ type: 'PROFILES_GET', payload: profiles })
    dispatch({ type: 'LOADING_SUCCESS' })
  } catch (error) {
    dispatch({ type: 'LOADING_FAILED', payload: error })
    throw error;
  }
}

async function deleteProfile(dispatch, profile) {
  dispatch({ type: 'LOADING_START' })
  try {
    console.log({ profile });
    const updatedProfile = await client.deleteProfile(profile)
    const profiles = await client.getProfiles()
    dispatch({ type: 'PROFILES_GET', payload: profiles })
    dispatch({ type: 'LOADING_SUCCESS' })
  } catch (error) {
    dispatch({ type: 'LOADING_FAILED', payload: error })
    throw error;
  }
}

export {
  ProfileProvider,
  useProfile,
  addProfile
}

这是我使用上下文的表单

function Form() {
  const { register, handleSubmit } = useForm();
  const [{ formType, profile }, profileDispatch] = useProfile();

  const buttonText = formType === 'Create' ? 'Create' : 'Edit';

  React.useEffect(() => {
    if(formType === 'Edit'){
      // populate input values
      ...
    }
  }, [formType])

  const onSubmit = data => {
    if (formType === 'Create') {
      addProfile(profileDispatch, data).catch(error => {
        toast(error);
      })
    } else {
      updateProfile(profileDispatch, data).catch(error => {
        toast(error);
      })
    }
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name", { required: true })} />
      <input {...register("age", { required: true })} />
      <button>{buttonText}</button>
    </form>
  )
}

标签: reactjsreact-native

解决方案


推荐阅读