reactjsreact-nativereact-native-keychain

React Native conditional rendering based on token without storage inside component state


I am currently using react-native-keychain to securely store access tokens. This is working well under most circumstances, but I am having problems trying to conditionally render a component based on the token being available or not.

Currently my code looks something like this:

function Questionnaire() {
  const [token, setToken] = useState(null);

  Keychain.getGenericPassword().then(credentials => {
    const token = credentials.password.replace('Bearer ', '');
    setToken(token);
  });

  if (token != null) {
    return (
      <WebView
        source={{
          uri: `url?token=${token}`,
        }}
        ...
      />
    );
  } else {
    return <Text>Loading...</Text>;
  }
}

Conditional rendering works here, but I am storing the token plainly in the state, which I want to avoid.

I tried doing something like this:

function Questionnaire() {
  const [token, setToken] = useState(null);

  return (
    <View>
      {(() => {
        Keychain.getGenericPassword().then(credentials => {
          const token = credentials.password.replace('Bearer ', '');
          return
            (
               <View>
                  ... // do something with the token
               </View>
            );
        });
      })()}
    </View>
  );
}

But this just returns nothing (because of it being a promise probably).

How could I go about solving this kind of problem?

EDIT

I have also tried fetching the web page and putting it in the state. The problem with this is that this is only an html page, so the page rendered in the webview is not very functional.


Solution

  • I have chosen to still store the token in the state, but to reset the token in a anonymous cleanup function in a useEffect hook.

    function Questionnaire() {
      const [token, setToken] = useState(null);
      const navigation = useNavigation();
    
      useEffect(() => {
        Keychain.getGenericPassword().then(credentials => {
          const token = credentials.password.replace('Bearer ', '');
          setToken(token);
        });
        return () => {
          setToken(null); // reset the token stored in the questionnaire state (token can still be retrieved from keychain)
        };
      }, []);
    
      return token ? (
        <WebView
          source={{
            uri: url?token=${token},
          }}
          ...
        />
      ) : (
        <Text>Loading...</Text>
      );
    }