我有一个PageContext
,它以数组的形式保存着User
对象的状态。每个User
对象都包含一个ScheduledPost
对象,当用户决定添加新帖子时,该对象会发生变异。我不知道如何在PageContext
发生时触发更新(我想避免进行forceUpdate()
通话)。我需要以某种方式得到通知,以便重新呈现帖子,维护计时器等。
请查看代码:
class User {
name: string;
createTime: number;
scheduledPosts: ScheduledPost[] = [];
/*
* Creates a new scheduled post
*/
public createScheduledPost(title : string, content : string, date : number): void {
this.scheduledPosts.push(Object.assign(new ScheduledPost(), {
title,
content,
date
}));
}
}
class ScheduledPost {
title: string;
content: string;
date: number;
public load(): void {
// Create timers etc.
}
public publish(): void {
// Publish post
}
}
// PageContext/index.tsx
export default React.createContext({
users: [],
editingUser: null,
setEditingUser: (user: User) => {}
});
// PageContextProvider.tsx
const PageContextProvider: React.FC = props => {
const [users, setUsers] = useState<User[]>([]);
const [editingUser, setEditingUser] = useState<User>(null);
// Load users
useEffect(() => {
db.getUsers()
.then(result => setUsers(result));
}, []);
return (
<PageContext.Provider value={{
users,
editingUser,
setEditingUser
}}>
{props.children}
</PageContext.Provider>
);
};
我想实现的是,使用useContext
钩子来使用我的提供程序时:
const ctx = useContext(PageContext);
我想从这样的任何组件创建日程表:
// Schedule post (1 hour)
ctx.editingUser.createScheduledPost("My post title", "The post content", (new Date).getTime() + 1 * 60 * 60);
但是,这不会起作用,因为React不知道User
属性刚刚发生了变异。
User
对象实例中的更改的通知?正确解决该问题的方法是什么(不包括forceUpdate)?答案 0 :(得分:3)
在哪里突变用户?如果您将它们存储在显示的状态,则应检测到更改。但是,如果您使用User类中内置的方法让它们自己directly update,那么React将不会使用它们。您需要在您的状态下更新整个users
数组,以确保React可以响应更改。
很难给出一个具体的示例,而又不知道您当前在何处/如何更新用户,但是一个广义的变异可能会发生这样的事情(如果需要,您仍然可以使用类方法):
const newUsers = Array.from(users); // Deep copy users array to prevent direct state mutation.
newUsers[someIndex].createScheduledPost(myTitle, myContent, myDate);
setUsers(newUsers); // Calling the setX function tied to your useState call will automatically trigger updates/re-renders for all (unless otherwise specified) components/operations that depend on it
答案 1 :(得分:1)
在React中,重新渲染是由在组件内调用setState
(或通过使用hooks,但要指出的是您需要调用特定方法)或更改组件props
引起的。这意味着您手动更改状态永远不会导致重新渲染-即使您使用简单的组件并称为
this.state.something = somethingElse;
不会发生重新渲染。同一件事适用于上下文。
对于您的情况,这意味着您不应更改editingUser
状态,而应使用已更改的用户状态调用setEditingUser
,例如:
const user = { ...ctx.editingUser };
user.createScheduledPost("My post title", "The post content", (new Date).getTime() + 1 * 60 * 60);
ctx.setEditingUser(user);
我不确定您的内部结构,但是如果同一用户也位于users
数组中,那么您将需要通过调用您维护的setUsers
方法来更新那部分状态整个数组,并且只更新更改数据的单个用户-如果是这种情况,那么我会考虑重组应用程序,因为对于这样简单的状态更改,它已经变得很复杂。您还应该考虑使用redux,mobx或其他状态管理库,而不是使用响应上下文(我的个人建议)。
编辑
请仔细看看:
在典型的React应用程序中,数据是自上而下传递的(对于 儿童)通过道具,但这对于某些类型的 许多人需要的道具(例如语言环境偏好设置,UI主题) 应用程序中的组件。上下文提供了一种共享方式 无需显式传递组件之间类似这些值 穿过树的每一层的道具。
如您所见,React团队建议对许多组件中所需的某些全局首选项使用上下文。使用上下文的主要问题(我认为)是,您没有编写 natural 反应组件-它们不会通过prop而是从上下文api本身接收相关数据。这意味着,如果不集成应用程序的上下文部分,就无法重用组件。
例如,虽然redux具有类似的将状态保持在一个位置的概念,但它仍通过props将该状态(及其更改)传播到组件,使您的组件不受redux,上下文或其他任何东西的依赖。
您可以坚持对上下文做出反应,并使整个应用程序都可以使用它,但是我只是说这样做不是最佳实践。