2017-09-16 64 views
0

我有這個流星應用程序發送數據到api,然後使用在網站發回的數據。但是,當我調用獲取api數據的函數,uploadToCloudinary()有一個回調,我發現它運行兩次。其中一個文檔正確插入正確的信息,另一個缺少res.data.secure_url。我是不是正在做回調事情,還是因爲它是非阻塞代碼,所以我認爲(糾正我,如果我錯了),當imageURL.push函數執行時,它不能找到一個res,所以它和其他代碼第一次,然後當它發現res它推它並創建另一個文檔。流星 - 回調執行兩次

import { Meteor } from "meteor/meteor" 
import React from "react"; 
import { withRouter, Link } from "react-router-dom"; 
import SimpleSchema from "simpl-schema"; 
import axios from "axios" 

import { SubjectRoutes } from "./subjectRoutes/subjectRoutes"; 
import "../methods/methods"; 
import Menu from "./subComponents/Menu"; 

class AddNote extends React.Component{ 
    constructor(props){ 
    super(props); 
    this.state = { 
     message: "", 
     loginMessage: (<div></div>), 
     urls: [] 
    }; 
    } 
    renderSubjects(subjects){ 
    return subjects.map((item) => { 
     return <option key={item}>{item}</option> 
    }) 
    } 
    componentWillMount() { 
    Meteor.subscribe('user'); 
    } 
    addNote(e){ 
    e.preventDefault(); 
    let title = this.refs.title.value; 
    let subject = this.refs.subject.value; 
    let description = this.refs.description.value; 
    let allUrls = [this.refs.imageURL.value].concat(this.state.urls); 
    let imageURL = allUrls.filter(function(entry) { return entry.trim() != ''; }); 
    let userId = Meteor.userId(); 
    let userEmail = Meteor.user().emails[0].address; 
    let createdAt = Date.parse(new Date()); 
    let unit = this.refs.unit.value; 
    let file = this.refs.fileInput.files[0]; 

    if(!Meteor.userId()){ 
     this.setState({ 
     message: "You need to login before you can add a note", 
     loginMessage: <Link to="/login">Login</Link> 
     }) 
     throw new Meteor.Error(400, "User is not signed in.") 
    } 

    if(title && subject && description && unit){ 
     if(imageURL.length == 0 && file == undefined){ 
     this.setState({ message: "You need to enter an image." }) 
     return; 
     } 
     console.log(imageURL.length, file) 
     if(imageURL){ 
     let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit }; 

     Meteor.call("notes.insert", noteInfo, (err, res) => { 
      if(err){ 
      this.setState({ message: "Please enter a valid image URL." }); 
      }else{ 
      this.props.history.push("/") 
      } 
     }) 
     } 
     if(file){ 
     let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit }; 

     this.uploadToCloudinary(file, (err, res) => { 
      imageURL.push(res.data.secure_url); 

      Meteor.call("notes.insert", noteInfo, (err, res) => { 
      //problem .......inserting 2 docs, one empty and one with proper data 
      console.log("CALLED") 
      if(err){ 
       this.setState({message: err.reason}); 
       console.log(err); 
      }else{ 
       this.props.history.push("/") 
      } 
      }) 
     }); 
     } 
    } 
    } 
    addLink(){ 
    let file = this.refs.fileInput.files[0]; 
    if(this.refs.imageURL.value || file != undefined){ 
     if(this.state.urls.length < 10){ 
     if(!this.state.urls.includes(this.refs.imageURL.value)){ 
      const URLSchema = new SimpleSchema({ 
      imageURL:{ 
       type:String, 
       label:"Your image URL", 
       regEx: SimpleSchema.RegEx.Url 
      } 
      }).validate({ imageURL:this.refs.imageURL.value }) 

      let urls = this.state.urls.concat([this.refs.imageURL.value]); 
      this.setState({ urls }); 
      this.refs.imageURL.value == ""; 
     }else{ 
      this.setState({ message: "You already inserted this note." }) 
     } 
     }else{ 
     this.setState({ message: "Only allowed 10 notes per upload. "}) 
     } 
    }else{ 
     this.setState({ message: "Please enter a note." }) 
    } 
    } 
    uploadToCloudinary(file, callback){ 
    const CLOUDINARY_URL = "MY_CLOUDINARY_URL"; 
    const CLOUDIARY_UPLOAD_PRESET = "MY_CLOUDIARY_UPLOAD_PRESET" 
    let formData = new FormData(); 

    formData.append("file", file); 
    formData.append("upload_preset", CLOUDIARY_UPLOAD_PRESET) 

    axios({ 
     url: CLOUDINARY_URL, 
     method: "POST", 
     headers: { 
     "Content-Type": "application/x-www-form-urlencoded" 
     }, 
     data: formData 
    }).then(function(res){ 
     callback(new Meteor.Error(400, "Error, cannot connect to cloudinary."), res); 
    }).catch(function(err){ 
     console.log(err); 
    }) 
    console.log(file); 
    } 
    render(){ 
    return(
     <div> 
     <form onSubmit={this.addNote.bind(this)}> 
      <Menu /> 
      <p>*Just a friendly reminder: If you cannot read the note yourself, 
      others cannot as well. Please make sure your notes are clear and 
      easy to read.*</p> 
      <h1>Add a note</h1> 
      <br /> 
      <input className="addNote-input" id="title" ref="title" type="text" placeholder="Title" autoComplete="off" /> 
      <br /> 
      <select ref="subject"> 
      <option selected disabled value="">Choose a subject</option> 
      {this.renderSubjects(SubjectRoutes)} 
      </select> 
      <br /> 
      <input className="addNote-input" id="description" ref="description" placeholder="Description Here..." autoComplete="off" /> 
      <br /> 
      <Link to="/questions">What is this?</Link><br /> 
      <div className="inline full"> 
      <div className="left"> 
       <input id="imageUrl" className="addNote-input insert-link" ref="imageURL" placeholder="Enter image URL here" autoComplete="off" /> 
      </div> 
      or 
      <div className="right"> 
       <input className="addNote-input inline" type="file" ref="fileInput" onChange={this.readImage} id="fileInput" autoComplete="off"/> 
      </div> 
      <div className="full inline-block"> 
       <span onClick={this.addLink.bind(this)} id="addLink">+</span> 
       <span>({this.state.urls.length})</span> 
      </div> 
      </div> 

      <input className="addNote-input" placeholder="Subject Unit" type="text" ref="unit" autocomplete="off" /> 
      <br /> 
      <button>Add Note</button> 
      <br /> 
      <div className="alert alert-danger">Error: {this.state.message}</div> 
      <br /> 
      {this.state.loginMessage} 
     </form> 
     </div> 
    ) 
    } 
} 

export default withRouter(AddNote); 

PS的函數uploadToCloudinary()只接收數據作爲參數,並把它發送到一個API然後將其放入一個回調返回的對象。而且console.log("CALLED")只執行一次,這對我來說真是令人困惑,因爲它創建了兩個文檔,所以它應該運行兩次。提前致謝!

+0

請添加你的'uploadToCloudinary'函數的源代碼。 – Styx

+1

這是什麼代碼?有沒有火焰模板?何反應?那裏有什麼反應嗎?有一種常見的情況,即在反應性代碼塊中執行方法調用,並且結束運行的次數超過預期。 –

+0

@MichelFloyd它是一個反應組件的一部分我認爲爲簡單起見,放置運行兩次而不是整個組件的函數會更容易,但如果這是您需要的,我會發布上面的整個組件。 –

回答

0

你在addNote()調用notes.insert方法兩次:

  1. if (imageURL) { ... }
  2. if (file) { ... } - 這一個呼喚uploadToCloudinary第一,並增加了secure_urlimageURL
+0

謝謝,我忘了,如果數組是空的,它仍然存在....... –