Невозможно получить доступ к этому после выполнения HTTP-запроса внутри действия MobX - PullRequest
0 голосов
/ 11 апреля 2019

У меня есть действие MobX, называемое doLogin ().Он может получить доступ к this. перед выполнением HTTP-запроса, но как только HTTP-запрос будет выполнен, он станет undefined.Я пробовал разные итерации функций стрелок, привязок и т. Д. Около 4 часов и начинаю сходить с ума.

Я пытался использовать разные библиотеки HTTP-запросов (axios, request)а также Fetch API.Все дают одинаковый результат.

Я пытался использовать утилиту MobX runInAction(), хотя у меня не включен строгий режим.Тот же результат.

AuthStore.js

import { observable, action } from "mobx";
import axios from "axios";

class AuthStore {
  @observable token = "";
  @observable isLoggedIn = false;
  @observable loading = false;
  @observable error = null;

  @action setToken = (token) => {
    this.token = token;
    this.isLoggedIn = true;
    this.loading = false;
  }

  @action doLogin = (email, password) => {
    this.loading = true; // works as expected
    console.log("this before: ", this); // prints AuthStore

    axios.post('http://my-api.com/users/authenticate', {
      email: email,
      password: password
    })
    .then(function (response) {
      console.log("this after: ", this); // prints undefined
      this.setToken(response.data.response.token); // err
    })
    .catch(function (error) {
      console.log("Auth store error ", error);
    });
  }
}

const store = new AuthStore();
export default store;

Login.js

import React from "react";
import { Form, Input, Button, Checkbox } from 'antd';
import { inject, observer } from 'mobx-react';

import "./Login.less";


@inject('AuthStore')
@observer
export default class Login extends React.Component {
  componentDidMount() {
    // To disabled submit button at the beginning.
    this.props.form.validateFields();
  }

  handleSubmit = (e) => {
    e.preventDefault();
    this.props.form.validateFields((err, values) => {
      if (!err) {
        this.props.AuthStore.doLogin(values.email, values.password);
      }
    });
  }

  hasErrors = (fieldsError) => {
    return Object.keys(fieldsError).some(field => fieldsError[field]);
  }

  render() {
    const { loading } = this.props.AuthStore;

    const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = this.props.form;

    const emailError = isFieldTouched('email') && getFieldError('email');
    const passwordError = isFieldTouched('password') && getFieldError('password');

    return (
      <div id="login">

        <Form onSubmit={this.handleSubmit} className="login-form">

          <Form.Item validateStatus={emailError ? 'error' : ''} help={emailError || ''}>
            {getFieldDecorator('email', {
              rules: [{ required: true, message: 'Please input your email!' }],
            })(
              <Input prefix={<i className="far fa-user"></i>} placeholder="Username" />
            )}
          </Form.Item>
          <Form.Item validateStatus={passwordError ? 'error' : ''} help={passwordError || ''}>
            {getFieldDecorator('password', {
              rules: [{ required: true, message: 'Please input your Password!' }],
            })(
              <Input prefix={<i className="far fa-lock"></i>} type="password" placeholder="Password" />
            )}
          </Form.Item>
          <Form.Item>
            {getFieldDecorator('remember', {
              valuePropName: 'checked',
              initialValue: true,
            })(
              <Checkbox>Remember me</Checkbox>
            )}
            <a className="login-form-forgot" href="">Forgot password</a>
            <Button type="primary" htmlType="submit" className="login-form-button" loading={loading} disabled={this.hasErrors(getFieldsError())}>
              Log in
            </Button>
            Don't have an account? <a href="">Register now!</a>
          </Form.Item>
        </Form>
      </div>
    );
  }
}

Login = Form.create({})(Login);

Я ожидаю, что смогу вызвать this.setToken (response.data.response.token) в моем действии после получения ответа от API, но я не могу.

edit:

Я исправил это с помощью $this=this.Не уверен, что это правильный способ решения проблемы, но это всего лишь личный проект, и после того, как я уже потратил часы на эту одну функцию, я закончил.

Так что теперь это выглядит как

@action doLogin = (email, password) => {
    const $this = this
    this.loading = true; // works as expected

    axios.post('http://my-api.com/users/authenticate', {
      email: email,
      password: password
    })
    .then(function (response) {
      $this.setToken(response.data.response.token);
    })
    .catch(function (error) {
      console.log("Auth store error ", error);
    });
  }

1 Ответ

0 голосов
/ 12 апреля 2019

Проблема, с которой вы столкнулись, не связана ни с одной из библиотек, упомянутых в посте. Вы должны выяснить, как this и function взаимодействуют друг с другом в JavaScript.

Это отличное место для начала: https://github.com/getify/You-Dont-Know-JS/tree/master/scope%20%26%20closures. После этого вам потребуется 10 секунд, чтобы обнаружить ошибку, не понимая, как работают MobX или axios (проблема не связана с этими библиотеками) , Это может звучать грубо, но сейчас, потратив 2 часа на освоение этой важной концепции JS, вы сэкономите много раз на 4 часа в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...