React Hook触发重新渲染,但React Navigation不会更新屏幕

时间:2020-07-29 19:02:03

标签: reactjs react-native react-hooks react-navigation

我写了一个useAuth钩子。通过此钩子,我使用partnerId中的var App.js来构建StackNavigator屏幕。我期望,当我设置/取消设置partnerId时,用户会自动导航到PairingDashboard组件,因为React Navigation会删除其中一个组件。 (如第一个代码段后面的here所述)

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

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

App.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;

dashboard.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;

useAuth.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;

1 个答案:

答案 0 :(得分:0)

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

答案是在useAuth()中调用App.js一次,然后使用React.createContext()将值传递给子组件。

App.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;

dashboard.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;