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
183 views
in Technique[技术] by (71.8m points)

reactjs - The value on the Context Provider doesn't change

So, I'm learning about React Context and try to implement it by creating an auth state for my React Native app. I tried following this Ben Awad's repo. This is what I've got so far:

// AuthContext.tsx
export const AuthContext = createContext<{
  user: null | string;
  login: () => void;
}>({
  user: null,
  login: () => {},
});

export const AuthProvider = ({ children }: Props) => {
  const [user, setUser] = useState<null | string>(null);
  const { user: contextUser } = useContext(AuthContext);

  return (
    <AuthContext.Provider
      value={{
        user,
        login: () => {
          setUser("My Name");
          console.log("Auth Provider pressed");
          console.log("user (state) " + user);
          console.log("contextUser (context) " + contextUser);
        },
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

// Navigation.tsx
export const Navigation = ({}: Props) => {
  const { user } = useContext(AuthContext);

  return (
    <AuthProvider>
        {user ? <HomeScreen /> : <Button />}
    </AuthProvider>

// Button.tsx
export const Button = ({}: Props) => {
  const { login } = useContext(AuthContext);

  return (
    <View>
        <Touchable
          onPress={login}
        >
          <Text style={styles.container}>Submit</Text>
        </Touchable>
    </View>
  )

The AuthProvider has 2 values. user which is obtained from the useState(). And, login which calls the setUser to change the user on the useState() and thus should change the user on the first Provider value.

The onPress on Button will call login() from the AuthProvider. The login() on the AuthProvider will trigger setUser to change the user on the useState() value from null to "My Name". Until this part, it works as expected.

But, even though the button successfully changes the user value on the useState(). It doesn't change the user (changed to contextUser for "debugging" purpose) on the Context, no mater how many times I click the button, the contextUser will always be null.

Tl;dr: user value on AuthProvider doesn't change after the button is pressed. But, user on useState changes.

So, what happened? What did I do wrong? Anyone has any idea how to fix this? I've stuck with this issue for the last few hours and googled more about this. My code is similar to theirs (I compared mine with other people's code that also uses context & auth), but somehow this code doesn't work.

Anyway, on Navigation, it should also automatically re-renders (to be HomeScreen) after the user value on Context is changed to non-null. I still haven't tested if it'll work (well, the user value never changes). Anyone could also review it to see if it could also run as expected?

question from:https://stackoverflow.com/questions/65843980/the-value-on-the-context-provider-doesnt-change

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

1 Reply

0 votes
by (71.8m points)

The issue is that you are consuming the context const { user } = useContext(AuthContext); in a component (Navigation) which is not a child of the AuthProvider.

At the moment your Navigation component is only receiving the context's default state. If you add a console.log to your context default state's login method, you will see this executed, rather than the contextual login method which is returned as the context's value. E.g:

// AuthContext.tsx
export const AuthContext = createContext<{
  user: null | string;
  login: () => void;
}>({
  user: null,
  login: () => {
    // this will run if there is no context provider when being called
    console.log('i am not working as expected')
  },
});

However, your Button component is receiving the full context, since it is a child of the Provider, and is updating the state.

If you move the AuthProvider "up a level" so that it is a parent of your Navigation component, then the Navigation component will also receive the updated context data.

E.g:

const Wrapper = () => (
  <AuthProvider> 
    <Navigation />
  </AuthProvider>
)

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

...