Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update context when state object mutates

I have a PageContext that is holding the state of User objects as array. Each User object contains a ScheduledPost object that does mutate when user decides to add a new post. I have no idea how to trigger an update on my PageContext when it happens (I want to avoid forceUpdate() call). I need to somehow be notified of that, in order to re-render posts, maintain timer etc.

Please, see the code:

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>
    );
};

What I would like to achieve is, when consuming my provider with useContext hook:

const ctx = useContext(PageContext);

I would like to create a schedule post from any component like so:

// Schedule post (1 hour)
ctx.editingUser.createScheduledPost("My post title", "The post content", (new Date).getTime() + 1 * 60 * 60);

However, this wont work, since React doesn't know that User property has just mutated.


Questions:

  • How can I make React being notified of the changes within any of the User object instance? What is the way to solve it properly (excluding forceUpdate)?
  • Am I doing it right? I'm new to React and I feel like the structure I'm using here is cumbersome and just not right.
like image 703
RA. Avatar asked Jul 10 '26 02:07

RA.


1 Answers

Where are the users being mutated? If you're storing them in your state as it appears, the changes should be detected. However if you're using the methods built into the User class to let them directly update themselves, then React will not pick up on them. You would need to update the entire users array in your state to make sure React can respond to the changes.

It's tough to give a more specific example without seeing exactly where/how you're updating your users currently, but a generalized mutation might go something like this (you can still use a class method, if desired):

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
like image 72
Chris B. Avatar answered Jul 11 '26 15:07

Chris B.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!