简体   繁体   中英

quick question about react context and rerendering components

I just started playing with context today and this is my usercontext

import { createContext, useEffect, useState } from "react";
import axios from "axios";

export const userContext = createContext({});
const UserContext = ({ children }) => {
  const [user, setUser] = useState({});

  useEffect(() => {
    axios.get("/api/auth/user", { withCredentials: true }).then((res) => {
      console.log(res);
      setUser(res.data.user);
    });
  }, []);

  return <userContext.Provider value={user}>{children}</userContext.Provider>;
};

export default UserContext;

this is how im using it in any component that needs the currently logged in user

const user = useContext(userContext)

my question is whenever the user logs in or logs out I have to refresh the page in order to see the change in the browser. is there any way that I can do this where there does not need to be a reload. also any general tips on react context are appreciated

(EDIT) this is how Im using the UserContext if it helps at all

const App = () => {
  return (
    <BrowserRouter>
      <UserContext>
        <Switch>
          {routes.map((route) => (
            <Route
              key={route.path}
              path={route.path}
              component={route.component}
            />
          ))}
        </Switch>
      </UserContext>
    </BrowserRouter>
  );
};

Where is your context consumer?

The way it is set up, any userContext.Consumer which has a UserContext as its ancestor will re render when the associated user is loaded, without the page needing to be reloaded.

To make it clearer you should rename your UserContext component to UserProvider and create a corresponding UserConsumer component:

import { createContext, useEffect, useState } from "react";
import axios from "axios";

export const userContext = createContext({});
const UserProvider = ({ children }) => {
    const [user, setUser] = useState({});

    useEffect(() => {
        axios.get("/api/auth/user", { withCredentials: true }).then((res) => {
        console.log(res);
        // setting the state here will trigger a re render of this component
            setUser(res.data.user);
        });
    }, []);

    return <userContext.Provider value={user}>{children}</userContext.Provider>;
};

const UserConsumer = ({ children }) => {
    return (
        <userContext.Consumer>
            {context => {
                if (context === undefined) {
                    throw new Error('UserConsumer must be used within a UserProvider ')
                }
                // children is assumed to be a function, it must be used
                // this way: context => render something with context (user)
                return children(context)
            }}
        </userContext.Consumer>
     );
};

export { UserProvider, UserConsumer };

Usage example:

import { UserConsumer } from 'the-file-containing-the-code-above';
export const SomeUiNeedingUserInfo = props => (
    <UserConsumer>
        {user => (
            <ul>
                <li>{user.firstName}</>
                <li>{user.lastName}</>
            </ul>
         )}
    </UserConsumer>
)

To be fair, you could also register to the context yourself, this way for a functional component:

const AnotherConsumer = props => {
    const user = useContext(userContext);
    return (....);
}

And this way for a class component:

class AnotherConsumer extends React.Component {
    static contextType = userContext;
    render() {
        const user = this.context;
        return (.....);
    }
}

The benefit of the UserConsumer is reuasability without having to worry if you're in a functional or class component: it will used the same way.

Either way you have to "tell" react which component registers (should listen to) the userContext to have it refreshed on context change.

That's the whole point of context: allow for a small portion of the render tree to be affected and avoid prop drilling.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM