我有一个由几个输入组件组成的表格。表单数据通过React上下文和React钩子useContext
在这些兄弟组件之间共享和共享。
我正在为如何有选择地将数据异步加载到同一上下文中而苦恼。例如,如果浏览器URL为example.com/form
,则表单可以使用FormContext
提供的默认值加载(没问题)。但是,如果用户通过导航到example.com/form/:username/:form-id
返回完成先前编辑过的表单,则应用程序应该使用这两个数据点来获取数据。为了覆盖默认的空表单初始值,大概必须在FormContext内发生这种情况。
React.createContext
函数吗?FormContext
export const FormContext = React.createContext();
export const FormProvider = props => {
const defaultFormValues = {
firstName: "",
lastName: "",
whatever: "",
};
const [form, setForm] = useLocalStorage(
"form",
defaultFormValues
);
return (
<FormContext.Provider value={{ form, setForm }}>
{props.children}
</FormContext.Provider>
);
};
Reference for useLocalStorage
答案 0 :(得分:1)
我认为您要寻找的答案是Redux,而不是库,而是工作流程。我确实发现很好奇,React没有对此提供更多指导。我不确定其他人在做什么,但这就是我想出的。
首先,我确保将来自useReducer
的分派添加到上下文中。这是该接口:
export interface IContextWithDispatch<T> {
context: T;
dispatch: Dispatch<IAction>;
}
然后给出此上下文:
export interface IUserContext {
username: string;
email: string;
password: string;
isLoggedIn: boolean;
}
我可以这样做:
export const UserContext = createContext<IContextWithDispatch<IUserContext>>({
context: initialUserContext,
dispatch: () => {
return initialUserContext;
},
});
在顶层组件中,我记住上下文,因为我只想要一个实例。这就是我把它们放在一起的方式
import memoize from 'lodash/memoize';
import {
IAction,
IContextWithDispatch,
initialUserContext,
IUserContext,
} from './domain';
const getCtx = memoize(
([context, dispatch]: [IUserContext, React.Dispatch<IAction>]) =>
({ context, dispatch } as IContextWithDispatch<IUserContext>),
);
const UserProvider = ({ children }) => {
const userContext = getCtx(useReducer(userReducer, initialUserContext)) as IContextWithDispatch<
IUserContext
>;
useEffect(() => {
// api call to fetch user info
}, []);
return <UserContext.Provider value={userContext}>{children}</UserContext.Provider>;
};
您的userReducer将响应所有dispatch
的调用,并且可以进行API调用或调用其他服务来执行此操作等。reducer处理对context
的所有更改。
一个简单的reducer可能看起来像这样:
export default (user, action) => {
switch (action.type) {
case 'SAVE_USER':
return {
...user,
isLoggedIn: true,
data: action.payload,
}
case 'LOGOUT':
return {
...user,
isLoggedIn: false,
data: {},
}
default:
return user
}
}
我现在可以在组件中执行此操作:
const { context, dispatch } = useContext<IContextWithDispatch<IUserContext>>(UserContext);
其中UserContext
是从上面定义的export
导入的。
在您的情况下,如果您的路线example.com/form/:username/:form-id
没有它需要的数据,则可以dispatch
和action
并听取上下文以了解该操作的结果。您的reducer可以进行任何必要的api调用,并且您的组件不需要了解任何有关它的信息。
答案 1 :(得分:0)
设法完成了我想要的大部分工作。以下是说明最终产品基本概念的要点:https://gist.github.com/kwhitejr/df3082d2a56a00b7b75365110216b395
很高兴收到反馈!