0

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.

5eb
  • 14,798
  • 5
  • 21
  • 65

2 Answers2

0

React does not allow you to wait, defer, or delay rendering. You have to render something, and then you can replace it later, when your promise resolves. And you should place your side effects to useEffect hook or in componentDidMount lifecycle method.

  • I get what you're saying, but I still don't know how I would go about replacing the content in this case. I don't want the token to be stored in the state and storing the entire component in the state is bad practice. – 5eb Mar 22 '20 at 17:12
0

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>
  );
}
5eb
  • 14,798
  • 5
  • 21
  • 65