Почему в моей программе дважды вызывается axios

Я пытаюсь установить состояние профиля через redux. Однако почему-то мой аксиос вызывается дважды

моя база данных profile.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

// Create Schema
const ProfileSchema = new Schema({
  user: {
    type: Schema.Types.ObjectId,
    ref: "users"
  },
  preference: [
    {
      type: String
    }
  ],

  date: {
    type: Date,
    default: Date.now
  }
});

module.exports = Profile = mongoose.model("profile", ProfileSchema);

myCreatePreferences класс

import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import checkboxes from "./checkboxes";
import Checkbox from "./Checkbox";
import axios from "axios";
import { Redirect } from "react-router";
import { withRouter } from "react-router-dom";
import Select from "react-select";
import { getCurrentProfile } from "../../actions/profileActions";
const options = [
  { value: "Guns", label: "Guns" },
  { value: "Gay Marriage", label: "Gay Marriage" },
  { value: "Abortion", label: "Abortion" },
  { value: "IT", label: "IT" }
];

class CreatePreferences extends Component {
  constructor() {
    super();
    this.state = {
      selectedOption: [],
      fireRedirect: false
    };
    this.onSubmit = this.onSubmit.bind(this);
  }
  onSubmit(e) {
    e.preventDefault();
    let tempArray = [];

    for (let i = 0; i < this.state.selectedOption.length; i++) {
      tempArray[i] = this.state.selectedOption[i].value;
    }
    const preference = {
      tempArray
    };
    //axios
    // .post("/api/profile/", { tempArray: tempArray })
    //.then(res => res.data)
    // .catch(err => console.info(err));
    this.props.getCurrentProfile(preference);
    this.setState({ fireRedirect: true });
  }

  handleChangeEvent = selectedOption => {
    this.setState({ selectedOption });
    console.info(`Option selected:`, selectedOption);
  };

  render() {
    const { selectedOption } = this.state;
    console.info(selectedOption.value);
    const { fireRedirect } = this.state;
    return (
      <div>
        <form onSubmit = {this.onSubmit}>
          <Select
            value = {selectedOption}
            isMulti
            onChange = {this.handleChangeEvent}
            options = {options}
          />
          <input
            type = "submit"
            className = "btn btn-info btn-block mt-4"
            value = "Save Preferences"
          />
          {fireRedirect && <Redirect to = {"/"} />}
        </form>
      </div>
    );
  }
}
CreatePreferences.propTypes = {
  profile: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
  profile: state.profile
});

export default connect(
  mapStateToProps,
  { getCurrentProfile }
)(withRouter(CreatePreferences));

мой профиль

import axios from "axios";

import {
  GET_PROFILE,
  PROFILE_LOADING,
  GET_ERRORS,
  CLEAR_CURRENT_PROFILE
} from "./types";

//Get current profile

export const getCurrentProfile = preference => dispatch => {
  dispatch(setProfileLoading());
  axios
    .post("/api/profile", preference)
    .then(res =>
      dispatch({
        type: GET_PROFILE,
        payload: res.data
      })
    )
    .catch(err =>
      dispatch({
        type: GET_PROFILE,
        payload: { err }
      })
    );
};

//Profile Loading

export const setProfileLoading = () => {
  return {
    type: PROFILE_LOADING
  };
};
//Clear Profile
export const clearCurrentProfile = () => {
  return {
    type: CLEAR_CURRENT_PROFILE
  };
};

profileReducer.js

import {
  GET_PROFILE,
  PROFILE_LOADING,
  CLEAR_CURRENT_PROFILE
} from "../actions/types";

const initialState = {
  profile: null,
  profiles: null,
  loading: false
};

export default function(state = initialState, action) {
  switch (action.type) {
    case PROFILE_LOADING:
      return {
        ...state,
        loading: true
      };
    case GET_PROFILE:
      return {
        ...state,
        profile: action.payload,
        loading: false
      };
    case CLEAR_CURRENT_PROFILE:
      return {
        ...state,
        profile: null
      };
    default:
      return state;
  }
}

Редукс-хранилище класса index.js.

import { combineReducers } from "redux";
import authReducer from "./authReducer";
import errorReducer from "./errorReducer";
import profileReducer from "./profileReducer";
import postReducer from "./postReducer";
export default combineReducers({
  auth: authReducer,
  errors: errorReducer,
  profile: profileReducer,
  post: postReducer
});

Когда я отправляю данные из класса createPreference через profileActions через axios, я получаю два запроса на отправку axios. Сначала он заполняет предпочтение, как ожидалось, однако мгновенно выполняет другой вызов, и предпочтение снова устанавливается на null. Console.log (вызова)

preference: Array(2), _id: "5bbc73011f67820748fcd9ab", user: "5bb87db33cb39a844f0ea46a", date: "2018-10-09T09:21:05.968Z", __v: 0}
Dashboard.js:20 {preference: null, _id: "5bbc73011f67820748fcd9ab", user: "5bb87db33cb39a844f0ea46a", date: "2018-10-09T09:21:05.968Z", __v: 0}

Есть предложения, как это исправить?

Поскольку вы вызываете его в методе onSubmit, а это функция getCurrentProfile

evgeni fotia 10.10.2018 00:38

@evgenifotia Кажется, его когда-то называли. Не могли бы вы объяснить, где эти два звонка, чтобы я мог это исправить. Спасибо

Shadman Mahmood 10.10.2018 03:21

Я хочу сначала в чем-то убедиться. Можете ли вы сделать console.info("1111") после export const getCurrentProfile = preference => dispatch => { в my profileActionsclass

evgeni fotia 10.10.2018 10:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
6 011
1

Ответы 1

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

Что я сделал:

  1. onSubmit = {this.onSubmit} переименован в более стандартный декларативный метод this.handleSubmit.
  2. Вызывается this.setState() в методе класса handleSubmit для удаления значения selectedOption, затем в обратном вызове setState называется getCurrentProfile(value, history) (замените value своим tempArray)
  3. Поменял ваш <input type = "submit" ... /> на <button type = "submit" ... />
  4. Добавлен return для вызова axios.get(...) (я также включил версию async/await для getCurrentProfile, которая может быть проще для понимания - также замените вызов axios.get на вызов axios.post)
  5. Удален Redirect и вместо этого помещен перенаправление внутри создателя action как history.push('/'); (после успешной отправки запроса он перенаправляет пользователя обратно в "/" - в случае ошибки перенаправления нет)
  6. Всегда сохраняйте состояние редукции как 1: 1. Другими словами, если это массив, то он остается массивом (нетnull), если это строка, он остается строкой (нетnumber) ... и т. д. При использовании PropTypes, ваше приложение будет выдавать ошибки, если вы не сохраните этот шаблон 1: 1. Например, вы изначально устанавливаете profile: null, а затем устанавливаете его как profile: [ Object, Object, Object ... ]. Вместо этого изначально должно быть: profile: [].
  7. При использовании PropTypes избегайте неоднозначных типов, таких как object или array, и вместо этого опишите, как они структурированы.
  8. Из-за природы redux и того, как вы настраиваете свой компонент, вам не нужно отправлять setProfileLoading. Вы можете просто обновить свои данные, и подключенный компонент React обновится, чтобы отразить новое изменение. Отправка двух действий redux по отдельности в течение короткого периода времени, скорее всего, приведет к миганию компонента (подумайте об этом как о вызове this.setState() дважды в секунду друг за другом - это приведет к миганию вашего компонента).

Рабочий пример: https://codesandbox.io/s/ovjq7k7516

SelectOption.js

import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
import Select from "react-select";
import { clearCurrentProfile, getCurrentProfile } from "../actions";

const options = [
  { value: "todos?userId=1", label: "Todos" },
  { value: "comments?postId=1", label: "Comments" },
  { value: "users?id=1", label: "Users" },
  { value: "albums?userId=1", label: "Albums" }
];

class SelectOption extends Component {
  state = {
    selectedOption: []
  };

  handleSubmit = e => {
    e.preventDefault();
    const { getCurrentProfile, history } = this.props;
    const { value } = this.state.selectedOption;

    this.setState({ selectedOption: [] }, () =>
      getCurrentProfile(value, history)
    );
  };

  handleChangeEvent = selectedOption => this.setState({ selectedOption });

  render = () => (
    <div className = "container">
      <form onSubmit = {this.handleSubmit}>
        <Select
          value = {this.state.selectedOption}
          onChange = {this.handleChangeEvent}
          options = {options}
        />
        <div className = "save-button">
          <button type = "submit" className = "uk-button uk-button-primary">
            Save Preferences
          </button>
        </div>
        <div className = "clear-button">
          <button
            type = "button"
            onClick = {this.props.clearCurrentProfile}
            className = "uk-button uk-button-danger"
          >
            Reset Preferences
          </button>
        </div>
      </form>
    </div>
  );
}

export default connect(
  state => ({ profile: state.profile }),
  { clearCurrentProfile, getCurrentProfile }
)(withRouter(SelectOption));

SelectOption.propTypes = {
  clearCurrentProfile: PropTypes.func.isRequired,
  getCurrentProfile: PropTypes.func.isRequired,
  profile: PropTypes.shape({
    profile: PropTypes.arrayOf(PropTypes.object),
    profiles: PropTypes.arrayOf(PropTypes.object),
    loading: PropTypes.bool
  }).isRequired
};

действия / index.js

import axios from "axios";
import { GET_PROFILE, PROFILE_LOADING, CLEAR_CURRENT_PROFILE } from "../types";

//Get current profile
export const getCurrentProfile = (preference, history) => dispatch => {
  // dispatch(setProfileLoading()); // not needed 
  return axios
    .get(`https://jsonplaceholder.typicode.com/${preference}`)
    .then(res => {
      dispatch({
        type: GET_PROFILE,
        payload: res.data
      });
      // history.push("/") // <== once data has been saved, push back to "/"
    })
    .catch(err =>
      dispatch({
        type: GET_PROFILE,
        payload: { err }
      })
    );
};

//Get current profile (async/await)
// export const getCurrentProfile = (preference, history) => async dispatch => {
//   try {
//     dispatch(setProfileLoading()); // not needed

//     const res = await axios.get(
//       `https://jsonplaceholder.typicode.com/${preference}`
//     );

//     dispatch({
//       type: GET_PROFILE,
//       payload: res.data
//     });

//     // history.push("/") // <== once data has been saved, push back to "/"
//   } catch (e) {
//     dispatch({
//       type: GET_PROFILE,
//       payload: { e }
//     });
//   }
// };

//Profile Loading
export const setProfileLoading = () => ({ type: PROFILE_LOADING });
//Clear Profile
export const clearCurrentProfile = () => ({ type: CLEAR_CURRENT_PROFILE });

редукторы / index.js

import { combineReducers } from "redux";
import { CLEAR_CURRENT_PROFILE, GET_PROFILE, PROFILE_LOADING } from "../types";

const initialState = {
  profile: [],
  profiles: [],
  loading: false
};

const profileReducer = (state = initialState, { type, payload }) => {
  switch (type) {
    case PROFILE_LOADING:
      return {
        ...state,
        loading: true
      };
    case GET_PROFILE:
      return {
        ...state,
        profile: payload,
        loading: false
      };
    case CLEAR_CURRENT_PROFILE:
      return {
        ...state,
        profile: []
      };
    default:
      return state;
  }
};

export default combineReducers({
  profile: profileReducer
});

Большое спасибо добрый сэр

Shadman Mahmood 12.10.2018 01:21

Другие вопросы по теме