【问题标题】:React Native Axios -> wait for async response and navigate to new page if trueReact Native Axios -> 等待异步响应,如果为真则导航到新页面
【发布时间】:2020-11-02 09:18:13
【问题描述】:

我在 React-Native 应用程序中使用 axios 发送带有用户凭据的 POST:

const LoginScreen = ({ navigation }) => {
  const [user, setUser] = useState('');
  const [pass, setPass] = useState('');

  async function onLoginPress() {
    await sendtoapi(user, pass);
    if(login==true){
      alert('Success, redirect to Details')
      navigation.navigate('Details');
    }
  ;}

  return (
    <View style={{ flex: 1, alignItems: 'center'}}>
          <Text style={styles.logoText}>App</Text>
            <TextInput placeholder="Username" placeholderColor="#c4c3cb" style={styles.loginFormTextInput} onChangeText={user => setUser(user)} />
            <TextInput placeholder="Password" placeholderColor="#c4c3cb" style={styles.loginFormTextInput} secureTextEntry={true} onChangeText={pass => setPass(pass)}/>
            <Button
              buttonStyle={styles.loginButton}
              onPress={() => onLoginPress()}
              title="Login"
            />
    </View>
  );
};

这是 axios 函数(sendtoapi):

async function sendtoapi(user, pass){
  var data = JSON.stringify({"user":user,"pass":pass});
  var config = {
    method: 'post',
    url: 'http://localhost/api/dev/',
    headers: { 
      'Content-Type': 'application/json'
    },
    data : data
  };
  
  axios(config)
  .then(function (response) {
    var res = response.data;
    if(res.login==true){
      login = true;
    }
  })
  .catch(function (error) {
    console.log(error);
  });
}

基本上这段代码可以工作,但我必须点击“登录”按钮两次,因为在 await sendtoapi(user, pass) 之后 var login 似乎没有设置为 true ; 所以它不等待。什么会导致这个问题?

【问题讨论】:

  • 不要使用这样的全局变量。如果登录有效,则从 sendToApi 返回 true,否则返回 false。在 onLoginPress() 你这样做:const loggedIn = await sendtoapi(user, pass);
  • 这是有道理的,但我在这里也有同样的问题。当我在 const loggedIn = await sendtoapi(user, pass); 之后使用 loggedIn 时,它仍然是未定义的。

标签: reactjs react-native axios


【解决方案1】:

这不是为了获取值而双击的问题,您的sendtoapi 函数没有返回 Promise(与网络请求有关)。

重构您的代码,使其返回axios 的Promise,然后处理全局login 参数的代码将仅在服务器响应后运行。

function sendtoapi(user, pass) {
  var data = JSON.stringify({ user: user, pass: pass });
  var config = {
    method: 'post',
    url: 'http://localhost/api/dev/',
    headers: {
      'Content-Type': 'application/json',
    },
    data: data,
  };

// --∨ this is required in order to the outer `await` will wait for the network request
  return axios(config)
    .then(function (response) {
      var res = response.data;
      return { isLoggedIn: res.login }; // it is better to return your "promised" value to the consumer
    })
    .catch(function (error) {
      console.log(error);
    });
}

对消费者代码的小重构

const LoginScreen = ({ navigation }) => {
  const [user, setUser] = useState('');
  const [pass, setPass] = useState('');

  async function onLoginPress() {
    const { isLoggedIn } = await sendtoapi(user, pass);
    // ---------^ the value which your promise returns
    if (isLoggedIn === true) {
      alert('Success, redirect to Details');
      navigation.navigate('Details');
    }
  }

  return (
    <View style={{ flex: 1, alignItems: 'center' }}>
      <Text style={styles.logoText}>App</Text>
      <TextInput
        placeholder="Username"
        placeholderColor="#c4c3cb"
        style={styles.loginFormTextInput}
        onChangeText={(user) => setUser(user)}
      />
      <TextInput
        placeholder="Password"
        placeholderColor="#c4c3cb"
        style={styles.loginFormTextInput}
        secureTextEntry={true}
        onChangeText={(pass) => setPass(pass)}
      />
      <Button buttonStyle={styles.loginButton} onPress={() => onLoginPress()} title="Login" />
    </View>
  );
};

提示:不要将全局/模块变量用于此类任务,因为很难将其暴露给应用程序的其余部分。 我建议您将其存储在一些与反应相关的存储(上下文/状态)中。

【讨论】:

  • 这不仅回答了我的问题并解决了我的问题,还让我对 Await/Promise 有了更多的了解。非常感谢@felixmosh!
猜你喜欢
  • 2020-12-09
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-27
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
相关资源
最近更新 更多