ajax react 异步执行

2018-07-21 09:18:43 qq_38719039 阅读数 1704
import React, {  Component} from 'react';
import $ from 'jquery';
import Cropper from 'react-cropper';
//import 'cropperjs/dist/cropper.css';
import styles from 'cropperjs/dist/cropper.css';

class CropBox extends Component {
	constructor(props) {
		super(props);

		this.state = {
	      src: '',
	      close: this.props.close ? this.props.close : true,
	      url: this.props.url ? this.props.url : '',
	      uploadData: this.props.uploadData ? this.props.uploadData : {},
	      aspectRatio: this.props.aspectRatio ? this.props.aspectRatio : ''
	    }

	    this.onChange = this.onChange.bind(this);
	    this.cropImage = this.cropImage.bind(this);
	    this.convertBase64UrlToBlob = this.convertBase64UrlToBlob.bind(this);
	    this.submitUpload = this.submitUpload.bind(this);
	    this.closeBox = this.closeBox.bind(this);
	}

	componentWillReceiveProps(nextProps) {
      this.setState({
         close: nextProps.close,
      });
    }

	onChange(e) {
	    e.preventDefault();
	    let files;
	    if (e.dataTransfer) {
	      	files = e.dataTransfer.files;
	    } else if (e.target) {
	      	files = e.target.files;
	    }
	    let reader = new FileReader(); //????????
	    reader.onload = () => {
	      this.setState({
	        src: reader.result,
	      });
	    };
	    reader.readAsDataURL(files[0]);
	}

    //----------------------------- start 提交 -------------------------------------
	cropImage() {
	    if (typeof this.cropper.getCroppedCanvas() === 'undefined') {
	      return;
	    }

	    let img64Data = this.cropper.getCroppedCanvas().toDataURL();
	    let imgblobDate = this.convertBase64UrlToBlob(img64Data);
	    this.submitUpload(imgblobDate);
	}

	submitUpload(imgBlob) {
		let _this = this;
		let fd = new FormData();
		fd.append('file', imgBlob);
		for(let key in this.state.uploadData) {
			fd.append(key, this.state.uploadData[key]);
		}
        console.log('提交fd',fd);
		
		$.ajax({
		    url: this.state.url,
		    type: 'POST',
		    data: fd,
		    contentType: false,
		    processData: false,
		    dataType: 'json',
		    success: function (data) {
	    		console.log(data.result);
	    		if(_this.props.getUrl) {
	    			_this.props.getUrl(data.result);
	    		}
	    		_this.setState({
	    			close: true,
	    			src: ''
	    		})
		    },
		    error: function(err) {
		    	console.log(err);
		    }
		});
	}


	//base64 转 二进制文件格式
	convertBase64UrlToBlob(urlData) {
		var bytes = window.atob( urlData.split(',')[1]);  //去掉url的头,并转换为byte

    //处理异常,将ascii码小于0的转换为大于0
    var ab = new ArrayBuffer(bytes.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    return new Blob( [ab], {type : 'image/png'});
	}
  //----------------------------- end ---------------------------------------

	closeBox() {
		this.setState({
			close: true
		})
	}

	render() {
		return (
			<div className ={styles["crop-box"]} style={this.state.close ? {"display": "none"} : {"display": "block"}}>
				<div className={styles["crop-box-bg"]}></div>
				<div className={styles["crop-box-content"]}>
					<div className={styles["crop-input"]}>
						<input type="file" onChange={this.onChange} />
						<div className={styles["crop-close"]} onClick = {this.closeBox}>关闭</div>
					</div>

					<div className={styles["crop-area"]}>
						<Cropper
				        style={{ height: 400, width: 400 }}
						    aspectRatio = {this.state.aspectRatio}
						    preview= ".img-preview"
                guides={true}
                src={this.state.src}
                ref={cropper => { this.cropper = cropper; }}
            />
					</div>
					<button className={styles["crop-sure-btn"]} onClick={this.cropImage}>确认裁剪</button>
				</div>
			</div>
		);
	}
}

export default CropBox;

 jQuery的 ajax进行异步请求。

2018-07-15 19:09:08 gao449812984 阅读数 13577

对于同步的状态改变,是可以放在componentWillMount,对于异步的,最好好放在componentDidMount。但如果此时有若干细节需要处理,比如你的组件需要渲染子组件,而且子组件取决于父组件的某个属性,那么在子组件的componentDidMount中进行处理会有问题:因为此时父组件中对应的属性可能还没有完整获取,因此就让其在子组件的componentDidUpdate中处理。

至于为什么,先看看react的生命周期

constructor() 》componentWillMount() 》render() 》componentDidMount()

上面这些方法的调用是有次序的,由上而下,也就是当说如果你要获取外部数据并加载到组件上,只能在组件"已经"挂载到真实的网页上才能作这事情,其它情况你是加载不到组件的。


componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。此外,在这方法中调用setState方法,会触发重渲染。所以,官方设计这个方法就是用来加载外部数据用的,或处理其他的副作用代码。


constructor被调用是在组件准备要挂载的最一开始,所以此时组件尚未挂载到网页上。


componentWillMount方法的调用在constructor之后,在render之前,在这方法里的代码调用setState方法不会触发重渲染,所以它一般不会用来作加载数据之用,它也很少被使用到。


一般的从后台(服务器)获取的数据,都会与组件上要用的数据加载有关,所以都在componentDidMount方法里面作。虽然与组件上的数据无关的加载,也可以在constructor里作,但constructor是作组件state初绐化工作,并不是设计来作加载数据这工作的,所以所有有副作用的代码都会集中在componentDidMount方法里。


constructor()中获取数据的话,如果时间太长,或者出错,组件就渲染不出来,你整个页面都没法渲染了。

componentDidMount()中能保证你的组件已经正确渲染。

总结下:

1.跟服务器端渲染(同构)有关系,如果在componentWillMount里面获取数据,fetch data会执行两次,一次在服务器端一次在客户端。在componentDidMount中可以解决这个问题。

2.在componentWillMount中fetch data,数据一定在render后才能到达,如果你忘记了设置初始状态,用户体验不好。

3.react16.0以后,componentWillMount可能会被执行多次。

2016-09-06 21:53:31 jl381169437 阅读数 3011

在动态 render 的时候,数据从后台获取,如果连不上网会阻塞页面加载,在写组件时碰到这个问题。查看 stackoverflow 提供两个方法:
一、将 ajax 请求放到父节点,通过 props 传值,不会造成阻塞

代码来自 stackoverflow: http://stackoverflow.com/questions/27192621/reactjs-async-rendering-of-components
var Parent = React.createClass({
  getInitialState: function() {
    return { data: null };
  },

  componentDidMount: function() {
    $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
      this.setState({data: data});
    }.bind(this));
  },

  render: function() {
    if (this.state.data) {
      return <CategoriesSetup data={this.state.data} />;
    }

    return <div>Loading...</div>;
  }
});

二、如果一定要在当前组件中使用,在执行 ajax 请求时先 render 别的内容

var CategoriesSetup = React.createClass({
  getInitialState: function() {
    return { data: null };
  },

  componentDidMount: function() {
    $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
      this.setState({data: data});
    }.bind(this));
  },

  render: function() {
    if (this.state.data) {
      return <Input type="select">{this.state.data.map(this.renderRow)}</Input>;
    }

    return <div>Loading...</div>;
  },

  renderRow: function(row) {
    return <OptionRow obj={row} />;
  }
});
2019-06-02 17:15:57 youlinaixu 阅读数 1600
npm install redux-thunk

引入中间件applyMiddleware
在这里插入图片描述
组件加载的时候去请求数据,派发一个action
在这里插入图片描述
在creatAction里面进行ajax数据的获取以及数据的派发
在这里插入图片描述
在reducer.js中对数据进行修改
在这里插入图片描述

2017-11-26 21:18:56 zrcj0706 阅读数 6664

1.设置 setTimeout定时器,通过延迟下一操作的执行时间,来解决ajax网络请求和下一操作异步的冲突(注意:时长的设置要大于等于网络请求的执行时间),代码如下

// 定义状态机
    constructor(props, context) {
        super(props, context);
        this.state = {
            content:null
        }
    }
//网络请求方法
Add = () => {  
    var formData = new FormData($("#userForm")[0]);  // 定位到userForm表单,并将表单定位转为FormData对象  
    $.ajax({  
      url: '/add',   //网络请求url地址  
      type: 'POST',  
      data: formData, //表单数据  
      cache: false,  
      contentType: false,  //或者 contentType:multipart/form-data均可以,multipart/form-data表示可以上传下载文件(既可以发送文本数据,也支持二进制数据上载),表明传输的数据要用到多媒体传输协议,由于多媒体传输的都是大量的数据,所以规定上传文件必须是post方法;contentType默认为application/x-www-form-urlencoded不能上传文件  
      processData: false,  
      success: function (data) {  
        console.log('成功'); this.setState({content:'修改成功'}) 
      }.bind(this),  
      error: function (xhr, status, err) {  
      }.bind(this)  
    });  
  }  
//执行操作
this.add();
setTimeout(() => {
               if(this.state.content=='修改成功'){alert('修改成功')}
				else{alert('修改失败')}
            }, 1000);
//如果不加1秒定时延迟,会直接进行判断,即未等网络请求结束便进行了判断

2.设置 ajax中参数async的属性

  • async:要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。
  • 通过该方式解决1中的异步问题,加上async:false, 代码如下
/ 定义状态机
    constructor(props, context) {
        super(props, context);
        this.state = {
            content:null
        }
    }

//网络请求方法
Add = () => {  
    var formData = new FormData($("#userForm")[0]);  // 定位到userForm表单,并将表单定位转为FormData对象  
    $.ajax({  
      url: '/add',   //网络请求url地址  
      type: 'POST',  
      data: formData, //表单数据 
	  async:false, 
      cache: false,  
      contentType: false,  //或者 contentType:multipart/form-data均可以,multipart/form-data表示可以上传下载文件(既可以发送文本数据,也支持二进制数据上载),表明传输的数据要用到多媒体传输协议,由于多媒体传输的都是大量的数据,所以规定上传文件必须是post方法;contentType默认为application/x-www-form-urlencoded不能上传文件  
      processData: false,  
      success: function (data) {  
        console.log('成功'); this.setState({content:'修改成功'}) 
      }.bind(this),  
      error: function (xhr, status, err) {  
      }.bind(this)  
    });  
  }  
//执行操作
this.add();
if(this.state.content=='修改成功'){alert('修改成功')}
else{alert('修改失败')}



react中使用ajax

阅读数 4348