Home.js =======> Parent component
import React, { useState, useReducer, useRef, createContext } from "react";
import { User1, User2, User3 } from "./User";
export const UserContext = createContext(null);
export const TypeContext = createContext(null);
const Home = () => {
const [user, setUser] = useState("User");
const [type, setType] = useState("Free");
return (
<>
<input type="text" onChange={(event) => setUser(event.target.value)} />
<br />
<input type="text" onChange={(event) => setType(event.target.value)} />
<UserContext.Provider value={{ user }}>
<User1 />
</UserContext.Provider>
<TypeContext.Provider value={{ type}}>
<User2 />
</TypeContext.Provider>
</>
);
};
export default Home;
User.js =============> Child Component
import React, { useContext, useMemo } from "react";
import { UserContext, TypeContext } from "./Home";
export const User1 = () => {
const { user } = useContext(UserContext);
console.log("user1");
return <h1>Username is {user}</h1>;
};
export const User2 = () => {
const { type } = useContext(TypeContext);
console.log("user2");
return <h1>Username is {type}</h1>;
};
export const User3 = React.memo((props) => {
console.log("user3");
return <h2>My Props {props.title}</h2>;
});
It re-renders User1 and User2 every time anything changes in user or type as the state of parent update. I want when I change user only User1 should update and when I update type only User2 should update
CodePudding user response:
Here is a working codesandbox that I created to handle your issue.
Explanation
You should memoize the child components if you want to render them only there is a change. Since you are not passing the values as props, you should also useMemo
the context provider values:
Home.js
import { useState, createContext, useCallback, useMemo } from "react";
import { User1, User2 } from "./User";
export const UserContext = createContext(null);
export const TypeContext = createContext(null);
export const Home = () => {
const [user, setUser] = useState("User");
const [type, setType] = useState("Free");
const handleUserChange = (event) => setUser(event.target.value);
const handleTypeChange = (event) => setType(event.target.value);
const userValue = useMemo(() => ({ user }), [user]);
const typeValue = useMemo(() => ({ type }), [type]);
return (
<>
<input type="text" onChange={handleUserChange} />
<br />
<input type="text" onChange={handleTypeChange} />
<UserContext.Provider value={userValue}>
<User1 />
</UserContext.Provider>
<TypeContext.Provider value={typeValue}>
<User2 />
</TypeContext.Provider>
</>
);
};
export default Home;
User.js
import { useContext, memo } from "react";
import { UserContext, TypeContext } from "./Home";
export const User1 = memo(() => {
const { user } = useContext(UserContext);
console.log("user1");
return <h1>Username is {user}</h1>;
});
export const User2 = memo(() => {
const { type } = useContext(TypeContext);
console.log("user2");
return <h1>Username is {type}</h1>;
});
CodePudding user response:
Changes to the context value will rerender all of the consumers, because React simply does an ===
comparison on the updated values, and you're creating the object inline (so it's different each time). See https://reactjs.org/docs/context.html#caveats
The solution is to memoize the value you pass to the provider, or use something like Redux or Zustand.
CodePudding user response:
you can use shouldComponentUpdate(nextProps, nextState)
for this method.
Use shouldComponentUpdate() to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior read docs here.
As a suggestion try not to use this unless absolutely necessary, this can cause bugs or performance issues but its the only method I know that is there so hpefully it helps