Как правильно обрабатывать HTTP-ответ в компоненте React Native? - PullRequest
1 голос
/ 08 апреля 2020

Я создаю мобильное приложение и использую Django REST Framework в качестве бэкэнда. И я также использую Redux. Одним из API, который я использую, является проверка кода OTP. Если код OTP совпадает, то я перенастраиваюсь с ответом от сервера, если это новый пользователь или нет. Если это новый пользователь, я перенаправлю его на экран регистрации, если нет, то я перенаправлю его на экран входа, это моя проблема.

Я храню ответ сервера в переменной с именем isNewUser в избыточном хранилище. Затем я обращаюсь к нему внутри моего компонента с помощью useSelector. Когда я нажимаю кнопку после ввода OTP-кода, я отправляю два действия. Первый, чтобы проверить OTP. Второе - это либо отправка для входа в систему, либо отправка для действия по регистрации, это зависит от переменной 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 Ответ

1 голос
/ 11 апреля 2020

Вы можете исправить эту проблему с небольшими изменениями. Проще всего это:

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);
    }
  };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...