在React Native组件中处理HTTP响应的正确方法是什么

时间:2020-04-08 13:23:34

标签: javascript reactjs react-native redux

我正在构建一个移动应用,并且我正在使用Django REST Framework作为后端。而且我也在使用Redux。我正在使用的API之一是验证OTP代码。如果OTP代码匹配,那么无论这是否是新用户,我都将根据服务器的响应进行调整。如果是新用户,则将其重定向到注册屏幕,如果不是新用户,则将其重定向到登录屏幕,这是我的问题。

我将服务器的响应存储在redux存储中名为isNewUser的变量中。然后,我使用useSelector在组件内部访问它。输入OTP代码后,单击按钮时,我将分派两个动作。首先验证OTP的人。第二个要么是用于登录的调度,要么是用于注册操作的调度,这取决于我从redux存储中获取的isNewUser变量。

问题是,当我分派第一个动作(即对OTP进行验证并存储isNewUser变量)时,直到下一次渲染时,该变量的值才会在我的组件中更新,因此我无法分派第二个动作,直到再次单击该按钮,以便更新变量的值。

那么如何解决呢?我不知道我的实现是否正确,或者有更好的实现。

这是我的操作代码,我尚未编写用于登录和注册操作的代码

export const validateOTP = (otp, mobileNum) => {
  return async dispatch => {
    const response = await fetch("http://localhost:8000/api/validate_otp", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        otp: otp,
        mobile: mobileNum
      })
    });
    if (!response.ok) {
      const errorResData = await response.json();
      console.log(errorResData);
    }

    const resData = await response.json();
    if (resData.status === false) {
      throw new Error(resData.detail);
    } else {
      const isNewUser = resData.isNewUser;
      dispatch({
        type: VALIDATE_OTP,
        isNewUser: isNewUser
      });
    }
  };
};

这是我的减速器代码:

import { VALIDATE_OTP } from "../actions/auth";

const initialState = {
  isNewUser: null
};

export default (state = initialState, action) => {
  switch (action.type) {
    case VALIDATE_OTP: {
      const isNewUserVal = action.isNewUser;
      return {
        ...state,
        isNewUser: isNewUserVal
      };
    }
  }
  return state;
};

这是来自React Native组件的示例代码:

const CodeEntryScreen = props => {
  const dispatch = useDispatch();
  const isNewUser = useSelector(state => state.auth.isNewUser)
  const [error, setError] = useState();


  useEffect(() => {
    if (error) {
      Alert.alert("An Error Occurred", error, [{ text: "Okay" }]);
    }
  }, [error]);

  const validateOTPHandler = async () => {
    setError(null);
    try {
      await dispatch(authActions.validateOTP(otp, mobileNum));
      console.log(isNewUser)
     if(isNewUser) {
        // dispatch resgister action
      }
      else {
        // dispatch  login action 
      }
    } catch (err) {
      setError(err.message);
    }
  };

1 个答案:

答案 0 :(得分:1)

您可以稍做修改即可解决此问题。较容易的是这样:

1)在您的dispatch中使用validateOTPHandler返回值

在您的validateOTP函数中,您将在结尾处添加以下内容:

dispatch({
  type: VALIDATE_OTP,
  isNewUser: isNewUser
});

让您的函数返回该值:

return dispatch({
  type: VALIDATE_OTP,
  isNewUser: isNewUser
});

有了这一更改,您就可以在组件中通过以下方式访问操作的负载:

  const validateOTPHandler = async () => {
    setError(null);
    try {
      const { isNewUser: isNew } = await dispatch(authActions.validateOTP(otp, mobileNum));
      console.log(isNew)
     if(isNew) {
        // dispatch resgister action
      }
      else {
        // dispatch  login action 
      }
    } catch (err) {
      setError(err.message);
    }
  };

这是更轻松的更改,可以根据需要进行操作。

2)useEffect

我认为这与您想到的流程更相似:

  • 验证代码(更新商店)
  • 重新渲染:您获得了新的价值
  • 现在要做的事情:登录或注册

但是,您需要使用useEffect来监听通过这种方式所做的更改:

const CodeEntryScreen = props => {
  const dispatch = useDispatch();
  const isNewUser = useSelector(state => state.auth.isNewUser)
  const [error, setError] = useState();
  const [success, setSuccess] = useState(false); // true when validateOTP succeeds

  useEffect(() => {
    if (error) {
      Alert.alert("An Error Occurred", error, [{ text: "Okay" }]);
    }
  }, [error]);

  useEffect(() => {
    if (success) {
      // validateOTP succeed... let's check isNewUser :)
      if (isNewUser) {
        // dispatch register
      } else {
        // dispatch login
      }
    }
  }, [success, isNewUser]);

  const validateOTPHandler = async () => {
    setError(null);
    setSuccess(false);
    try {
      await dispatch(authActions.validateOTP(otp, mobileNum));
      setSuccess(true);
    } catch (err) {
      setError(err.message);
    }
  };