首页 > 解决方案 > React Hook 触发重新渲染,但 React Navigation 不更新屏幕

问题描述

我写了一个useAuth钩子。从这个钩子中,我使用我的 varpartnerIdApp.js构建 StackNavigator 屏幕。我希望,当我设置/取消设置时partnerId,用户会自动导航到PairingorDashboard组件,因为 React Navigation 会删除其中一个。(如第一个代码片段后所述

所以当我运行应用程序时,我会看到仪表板,因为我使用了addPartner('test');. 当我单击仪表板上的按钮时,我看到组件重新渲染,因为<Text>节点从更改PartnerNo Partner.

但我希望被重定向到配对组件!

应用程序.js

const AppStack = createStackNavigator();

const App = () => {
  const [myId, partnerId, addPartner, removePartner] = useAuth();

  addPartner('test'); // for testing right now

  return (
    <NavigationContainer>
      <AppStack.Navigator>
        {!partnerId ? (
          <AppStack.Screen
            name="Pairing"
            component={Pairing}
            options={{headerShown: false}}
          />
        ) : (
          <AppStack.Screen
            name="Dashboard"
            component={Dashboard}
            options={{title: 'Dashboard'}}
          />
        )}
      </AppStack.Navigator>
    </NavigationContainer>
  );
};

export default App;

仪表板.js

const Dashboard = () => {
  const [myId, partnerId, addPartner, removePartner] = useAuth();

  return (
    <SafeAreaView>
      <ScrollView>
        <Text>Dashboard</Text>
        {partnerId ? <Text>Partner</Text> : <Text>No Partner</Text>}
        <Button
          title="Remove Partner Id"
          onPress={() => {
            removePartner();
          }}
        />
      </ScrollView>
    </SafeAreaView>
  );
};

export default Dashboard;

使用Auth.js

const PARTNERID_KEY = 'partnerId';
const MYID_KEY = 'myId';

const useAuth = () => {
  const [myId, setMyId] = useState(null);
  const [partnerId, setPartnerId] = useState(null);

  const removePartner = async () => {
    await AsyncStorage.removeItem(PARTNERID_KEY);
    setPartnerId(null);
    console.log('Removed Partner', partnerId);
  };

  const addPartner = async (newPartnerId) => {
    if (!newPartnerId) {
      console.error('newPartnerId is null/undefined');
      return false;
    }

    if (newPartnerId.toUpperCase() === myId.toUpperCase()) {
      console.error('newPartnerId and myId are equal');
      return false;
    }

    await AsyncStorage.setItem(PARTNERID_KEY, newPartnerId);
    setPartnerId(newPartnerId);
    console.log('Added Partner', partnerId);
    return true;
  };

  useEffect(() => {
    const init = async () => {
      // partner
      const storagePartnerId = await AsyncStorage.getItem(PARTNERID_KEY);
      if (storagePartnerId) {
        setPartnerId(storagePartnerId);
      }

      // self
      let storageMyId = await AsyncStorage.getItem(MYID_KEY);
      if (!storageMyId) {
        storageMyId = await UUIDGenerator.getRandomUUID();
        await AsyncStorage.setItem(MYID_KEY, storageMyId);
      }
      setMyId(storageMyId);

      console.log('Auth init', myId, partnerId);
    };
    init();
  }, [myId, partnerId]);

  return [myId, partnerId, addPartner, removePartner];
};

export default useAuth;

标签: reactjsreact-nativereact-hooksreact-navigation

解决方案


我发现不可能像全局单例一样使用 Hook(例如,像 Angular 服务),因为它不是单例

答案是调用useAuth()一次App.js并用于React.createContext()将值传递给子组件。

应用程序.js

const AppStack = createStackNavigator();
export const AuthContext = React.createContext();

const App = () => {
  const [myId, partnerId, addPartner, removePartner] = useAuth();

  const authContext = {myId, partnerId, addPartner, removePartner};
  addPartner('test'); // testing
  return (
    <AuthContext.Provider value={authContext}>
      <NavigationContainer>
        <AppStack.Navigator>
          {!partnerId ? (
            <AppStack.Screen
              name="Pairing"
              component={Pairing}
              options={{headerShown: false}}
            />
          ) : (
            <AppStack.Screen
              name="Dashboard"
              component={Dashboard}
              options={{title: 'Dashboard'}}
            />
          )}
        </AppStack.Navigator>
      </NavigationContainer>
    </AuthContext.Provider>
  );
};

export default App;

仪表板.js

const Dashboard = () => {
  const foo = React.useContext(AuthContext);
  return (
    <SafeAreaView>
      <ScrollView>
        <Text>Dashboard</Text>
        {foo.partnerId ? <Text>Partner</Text> : <Text>No Partner</Text>}
        <Button
          title="Remove Partner Id"
          onPress={() => {
            foo.removePartner();
          }}
        />
      </ScrollView>
    </SafeAreaView>
  );
};

export default Dashboard;

推荐阅读