Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
656 views
in Technique[技术] by (71.8m points)

javascript - How to solve problem with too many re-renders in context?

Whenever I update user (object) in users (array) in context - all components which uses users re-renders.


What I've tried

I have a component which is using values from context:

const DashboardCardList=()=> {
    const context = useContext(StaticsContext);
    const users = context.users.filter(user=>user.visible);

    return !users
        ? <Loading/>
        : (
            <Container>
                {users.map(user=>
                    <DashboardCard key={user._id} user={user}/>
                )}
            </Container>
        );
};

My update function (updates context state):

const onUserUpdate=(user)=>{
   const index = this.state.users.findIndex(item => item._id === user._id);
   const users = [...this.state.users]
   users[index] = user;
   this.setState({users:users});
}

Final component:

const DashboardCard=({user})=> {
    console.log("I'm here!", user);
    return ...;
}

Question

Why it keeps re-rendering? Is it because of context?
How to write this properly?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is no render bailout for context consumers (v17).

Here is a demonstration, where the Consumer will always re-render just because he is a Context Consumer, even though he doesn't consume anything.

import React, { useState, useContext, useMemo } from "react";
import ReactDOM from "react-dom";

// People wonder why the component gets render although the used value didn't change
const Context = React.createContext();

const Provider = ({ children }) => {
  const [counter, setCounter] = useState(0);
  const value = useMemo(() => {
    const count = () => setCounter(p => p + 1);
    return [counter, count];
  }, [counter]);
  return <Context.Provider value={value}>{children}</Context.Provider>;
};

const Consumer = React.memo(() => {
  useContext(Context);
  console.log("rendered");
  return <>Consumer</>;
});

const ContextChanger = () => {
  const [, count] = useContext(Context);
  return <button onClick={count}>Count</button>;
};

const App = () => {
  return (
    <Provider>
      <Consumer />
      <ContextChanger />
    </Provider>
  );
};

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

Edit Context API Problem

To fix it:

  • Use a single context for each consumed value. Meaning that context holds a single value, (and no, there is no problem with multiple contexts in an application).
  • Use a state management solution like Recoil.js, Redux, MobX, etc. (although it might be overkill, think good about app design beforehand).
  • Minor optimization can be achieved by memoizing Provider's values with useMemo.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...