1

I have an application where user has lot of profile information e.g LinkedIn profile. I need to update user's profile. I create a context at root level component i.e App and share that context using useContext hook in multiple profile components. The user can change the profile attributes like title, summary of his profile from any sub component and it updates the global context. When the global context refreshes then it causes all the child components that consume the context to re-render. How can I avoid re-render of other components where there was no change.

Here is my code:

profile-context.tsx

import React from 'react';
let ProfileContext = React.createContext({});
export default ProfileContext;

App.tsx

import React, { useEffect, useState } from 'react';
import UserProfile from './user-profile';
import ProfileContext from './context/profile-context';

const App = () => {
    const [userProfile, setProfileInfo] = useState({});

    const update = (profile: any, section: any, attributes: any) => {
        let updatedState = UserService.updateProfile(profile, section, attributes);//This returns the updated state
        setProfileInfo((prevState: any) => updatedState);
    };

    useEffect(() => {
        setProfileInfo(() => UserService.fetchProfileInfo());
    }, []);

    return (
        <>
            <ProfileContext.Provider value={{ userProfile, update }}>
              <UserProfile />
            </ProfileContext.Provider>
        </>
    );
};

export default App;

user-profile.tsx

    import React, { FC } from 'react'
    import Header from './profile/header';
    import About from './profile/about';
    import Experience from './profile/experience';
    import Education from './profile/education';

    
    const UserProfile: FC = () => {
        return (
            <>
                <Header />
                <About />
                <Experience />
                <Education />
            </>
        );
    };
    
    export default UserProfile;

about.tsx

import React, { FC, useContext } from 'react';

import ProfileContext from '../../../context/profile-context';

const About: FC = () => {
    let { userProfile, update } = useContext(ProfileContext);

    const changeProfileAttribute = (section: any, attribute: string) => {
        update(userProfile, section, { attribute: 'Software Engineer' });
    };


    return (
        <>
            <div className="user-profile">
             
                    <h1
                        className="professional-title"
                        onClick={() => {
                            changeProfileAttribute('about', 'title');
                        }}
                    >
                        {userProfile.about.title}
                    </h1>
                  
                </div>
            </div>
        </>
    );
};

export default About;

As I make a change About component by clicking on professional title (dummy function to update the state attribute) the whole application re-renders. I want that only about section of the profile should be updated as I only changed on attribute in about key of user profile object. FYI the user profile object looks like this in my application:

{
id: 1
about: {
  title: "Software Engineer",
  email: "james@gmail.com",
  first_name: "Duke",
  last_name: "James"

},
education: [],
experience: [],
recommendations: []


}

Is it possible with context API to only update certain part of state so that it does not re-render other context consumers where change did not occur? Please help.

Hammad
  • 2,097
  • 3
  • 26
  • 45

1 Answers1

0

Any child of a context provider will re-render if any of the values change, one way to go around this is by memoizing components that don't depend on the state/values in the context. You can read about memoized components here.

  • But all the profile sub components depend upon the values in context, so memoization does not help. – Hammad Mar 22 '22 at 18:54
  • If it depends on it then why do you want to prevent them from re-rendering? That doesn't make sense. – Nicolai Christensen Mar 22 '22 at 18:56
  • As I described in the question that I only change on attribute of state key, so I want the components that rely only those sub key should update. For example if I change title in about sub key of state then other components should not update because I did not change their sub keys like education, experience etc – Hammad Mar 22 '22 at 18:59
  • Yes, you can add dependencies to a memoized component, i suppose you could then add what they rely on in the dependencies. Fix: I'm unsure of that now, but in general you don't need to worry about unexpensive re-renders, or be careful with having too little contexts, break them up to where you need them. – Nicolai Christensen Mar 22 '22 at 19:00
  • Yes I tried this too but it still renders. I made all profile components to useMemo and returned memoized component so that when one componet changes then other should not re-render but they still do – Hammad Mar 22 '22 at 19:11
  • Split them up to a context for each thing instead of having 1 context. And place them in a smart manner. That's the best I can think of. – Nicolai Christensen Mar 22 '22 at 19:12
  • But aren't context meant to be global and should be kept at root level? Sorry I am new to react and may be wrong at many places. So you are saying that I should have multiple contexts for each profile section? Later in the appllication I have news feed, settings etc too. Then I will need context for each of those features too? – Hammad Mar 22 '22 at 19:14
  • Nope, they are not (: You place them around the components that need access to them and to minimize re-renders we create several instead of 1 for optimisation. By several I mean 1 context.provider for each, unless they're together. – Nicolai Christensen Mar 22 '22 at 19:15
  • Alright thanks. So I think I should keep the profileContext in userProfile component rather than in App component and should do the same with other components like NewFeed etc. I hope I understood correctly – Hammad Mar 22 '22 at 19:17
  • Yes, that would seem to be the case, if you run into needing it in a higher component you just raise the context to where you need it. – Nicolai Christensen Mar 22 '22 at 19:18
  • Alright. Your comments and time is helpful. I am just new to react and building an app for client. I need to be sure what I am doing is right way to do. – Hammad Mar 22 '22 at 19:19
  • All good, React is wonderful (: I've come to love it, and hope others will too! Have a good day. – Nicolai Christensen Mar 22 '22 at 19:20