history.push не работает при получении обратного вызова - PullRequest
0 голосов
/ 16 сентября 2018

Я работаю над приложением простого реагирования, в котором я аутентифицирую пользователя, и если он / она успешно вошел в систему, я пытаюсь перенаправить на домашнюю страницу, но нахожусь в какой-то странной ситуации.Пожалуйста, помогите мне с помощью приведенного ниже кода.

Ниже приведен код функции fetchAPI для вызова на сервер с некоторыми входными параметрами

function fetchAPI(methodType, url, data, callback){

    fetch(url,{
        method: methodType,
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)  
    })
    .then(response => response.json())
    .then(data => callback(data) )
    .catch(error => callback(data));  

}

Теперь я так называю

fetchAPI("POST", Constants.LOGIN, data, function(callback) {
        if(callback.status == 200) {
            console.log(callback.message);
            this.props.history.push("/home");
        }else if( typeof callback.status != "undefined"){
            alertModal("Alert", callback.message);
        }
      });

Проблема в том, что он не перенаправляет на /home, как указано в условии ответа, а только печатает сообщение об успехе.Но когда я непосредственно использую api fetch, как показано ниже, он перенаправляет меня на /home

Кто-нибудь может мне помочь, почему это происходит со мной ??

fetch(Constants.LOGIN, {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
      })
        .then(response => response.json())
        .then(data => {
          if (data.status == 200) {
            this.props.history.push("/home");
          } else if (typeof data.status != "undefined") {
            alertModal("Alert", data.message);
          }
        })
        .catch(error => callback(data));

1 Ответ

0 голосов
/ 16 сентября 2018

ОК, забудьте про обратные вызовы, я там уже был, не более ЗВОНОК АД .

Всегда используйте обещания, и вы можете упростить все, используя async / await:

async function fetchAPI(methodType, url, data){
    try {
        let result = await fetch(url, {
            method: methodType,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)  
        }); // wait until request is done
        let responseOK = response && response.ok;
        if (responseOK) {
            let data = await response.json();
            // do something with data
            return data;
        } else {
            return response;
        }
    } catch (error) {
        // log your error, you can also return it to handle it in your calling function
    }
}

в вашем Реактивном Компоненте:

async someFunction(){
    let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
    if (!result.error){
        // get whatever you need from 'result'
        this.props.history.push("/home");
    } else {
        // show error from 'result.error'
    }
}

Теперь ваш код выглядит более читабельным!

Ошибки извлечения находятся либо в result.error, либо в result.statusText, я давно перестал использовать fetch, переключился на Axios . Посмотрите на мой ответ о некоторых различиях между 2 Здесь .

РЕДАКТИРОВАТЬ НА ОСНОВЕ ВАШЕГО ОТВЕТА

Хорошо, на основании кода, который вы разместили:

import React from "react";
import Constants from "../Constants.jsx";
import { withRouter } from "react-router-dom";

class Login extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      email: "",
      password: "",
      errors: []
    };
  }

  showValidationErr(elm, msg) {
    this.setState(prevState => ({
      errors: [...prevState.errors, { elm, msg }]
    }));
  }

  clearValidationErr(elm) {
    this.setState(prevState => {
      let newArr = [];
      for (let err of prevState.errors) {
        if (elm != err.elm) {
          newArr.push(err);
        }
      }
      return { errors: newArr };
    });
  }

  onEmailChange(e) {
    this.setState({ email: e.target.value });
    this.clearValidationErr("email");
  }

  onPasswordChange(e) {
    this.setState({ password: e.target.value });
    this.clearValidationErr("password");
  }

  submitLogin(e) {
    e.preventDefault();

    const { email, password } = this.state;
    if (email == "") {
      this.showValidationErr("email", "Email field cannot be empty");
    }
    if (password == "") {
      this.showValidationErr("password", "Password field cannot be empty");
    }

    if (email != "" && password != "") {
      var data = {
        username: this.state.email,
        password: this.state.password
      };


        // I added function keyword between the below line
        async function someFunction(){
          let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
          if (!result.error){
              this.props.history.push("/home");  // Here is the error
          } else {
              // show error from 'result.error'
          }
        }
        someFunction();
    }


  }

  render() {  ......................

####-----This is function definition------####

async function fetchAPI(methodType, url, data){
    try {
        let response = await fetch(url, {
            method: methodType,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)  
        }); // wait until request is done
        let responseOK = response && response.ok;
        if (responseOK) {
            let data = await response.json();
            // do something with data
            return data;
        } else {
            return response;
        }
    } catch (error) {
        return error;
        // log your error, you can also return it to handle it in your calling function
    }
}

Это идея, вы должны сделать async функцией, которая вызывает API. В вашем примере ваша функция submitLogin должна быть асинхронной, поскольку она будет вызывать асинхронную функцию внутри. Пока вы вызываете асинхронную функцию, вызывающая сторона ДОЛЖНА быть асинхронной или обрабатывать обещание соответствующим образом. Вот как это должно быть:

  async submitLogin(e) {
    e.preventDefault();

    const { email, password } = this.state;
    if (email == "") {
      this.showValidationErr("email", "Email field cannot be empty");
    }
    if (password == "") {
      this.showValidationErr("password", "Password field cannot be empty");
    }

    if (email != "" && password != "") {
      var data = {
        username: this.state.email,
        password: this.state.password
      };

      let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
      if (!result.error) {
        this.props.history.push("/home");  // Here is the error
      } else {
        // show error from 'result.error'
      }
    }

Если функция правильно связана в конструкторе, у вас не возникнет проблем с this. Похоже, что вы не привязываете функцию submitLogin в конструкторе, что вызовет проблемы с контекстом this. Вот как это должно быть связано:

constructor(props) {
    super(props);
    this.state = {
      email: "",
      password: "",
      errors: []
    };

    // bind all functions used in render
    this.submitLogin = this.submitLogin.bind(this);
  }

Ознакомьтесь с этой статьей , чтобы узнать больше о проблеме с контекстом this.

Теперь, исходя из предоставленного вами кода, мне кажется, что вы находитесь на неизведанной территории. Если вам кажется, что вы находите маршрутизацию сложной или асинхронный / ожидающий неясен, я советую вам не использовать их и сначала освоить основы React (у вас есть проблема с синтаксисом, например, вы не должны поместите эту функцию туда, а также проблему связывания с this).

Прочтите, например, в этом посте , чтобы иметь общее представление, и я также предлагаю вам попробовать другие более простые примеры перед использованием async, fetch или routing. Когда вы очистите жизненный цикл React, вы сможете продолжить с него и использовать асинхронные функции, а затем маршрутизаторы.

Я также предлагаю вам следовать примерам в Официальных документах , а также взглянуть на этот пост , чтобы лучше понять async / await.

Эти предложения, конечно, даются, чтобы вы могли освоить React с четкими основами, и в будущем не будет никаких проблем с основами! :)

...