Javascript 为什么axios在我的程序中被调用了两次

Javascript 为什么axios在我的程序中被调用了两次,javascript,reactjs,axios,Javascript,Reactjs,Axios,我正试图通过redux设置配置文件状态。但是由于某些原因,我的axios被调用了两次 my database profile.js const mongoose = require("mongoose"); const Schema = mongoose.Schema; // Create Schema const ProfileSchema = new Schema({ user: { type: Schema.Types.ObjectId, ref: "users"

我正试图通过redux设置配置文件状态。但是由于某些原因,我的axios被调用了两次

my database 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.log(err));
    this.props.getCurrentProfile(preference);
    this.setState({ fireRedirect: true });
  }

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

  render() {
    const { selectedOption } = this.state;
    console.log(selectedOption.value);
    const { fireRedirect } = this.state;
    return (
      <div>
        <form onSubmit={this.onSubmit}>
          <Select
            value={selectedOption}
            isMulti
            onChange={this.handleChange}
            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));
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类redux存储

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
});
当我通过axios通过profileActions从createPreference类发布数据时,我收到了两个axios post请求。它首先按照预期填充首选项,但是它立即进行另一个调用,并且首选项再次设置为null


关于如何解决这个问题,有什么建议吗?

因为我无法访问您的所有代码(也无法调试),所以这里有一个更好的获取数据的方法。我已经将其结构与您所拥有的紧密结合,如果您遵循工作示例,您应该能够消除问题

我所做的:

  • onSubmit={this.onSubmit}
    重命名为更标准的声明性
    this.handleSubmit
    方法
  • handleSubmit
    类方法中调用
    this.setState()
    以删除
    selectedOption
    值,然后在setState回调中调用
    getCurrentProfile(value,history)
    (用
    tempArray
    替换
    值)
  • 将您的
    更改为
  • axios.get(…)
    调用添加了
    return
    (我还包括了
    async/await
    版本的
    getCurrentProfile
    ,这可能更容易理解,也可以用
    axios.get
    调用代替
    axios.post
    调用)
  • 删除了
    重定向
    ,而是将重定向放置在
    操作
    创建者中,作为
    历史。推送('/')(请求成功发送后,它将用户重定向回“/”——如果出错,则不重定向)
  • 始终保持你的redux状态为1:1。换句话说,如果它是一个数组,那么它将保持一个数组(
    null
    ),如果它是一个字符串,那么它将保持一个字符串(
    )…等等。使用
    PropTypes时,
    如果不保持1:1模式,应用程序将抛出错误。例如,您最初设置
    profile:null
    ,但随后将其设置为
    profile:[Object,Object,Object…]
    。相反,它最初应该是:
    profile:[]
  • 使用
    PropTypes
    时,避免使用诸如
    object
    array
    等不明确的类型,而是描述它们的结构
  • 由于redux的性质以及您如何设置组件,您不需要分派
    setProfileLoading
    。您只需更新数据,连接的React组件将更新以反映新的更改。在短时间内分别调度两个redux操作很可能会导致组件闪烁(可以将其视为在一秒钟内调用
    this.setState()
    两次,这将导致组件闪烁) 工作示例:

    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)
        );
      };
    
      handleChange = selectedOption => this.setState({ selectedOption });
    
      render = () => (
        <div className="container">
          <form onSubmit={this.handleSubmit}>
            <Select
              value={this.state.selectedOption}
              onChange={this.handleChange}
              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
    };
    
    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 });
    
    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
    });
    

    因为您在
    onSubmit
    Methode中调用它,并且它是
    getCurrentProfile
    function@evgenifotia我想有人会叫它一次。你能解释一下这两个电话在哪里吗?这样我就可以更正了。在
    export const getCurrentProfile=preference=>dispatch=>{
    in
    my Profile ActionsClass
    中,您能在
    export const getCurrentProfile=preference=>dispatch=>
    
    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 });
    
    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
    });