6

Try create upload function with cropper component. But when I try set state it says that

Uncaught TypeError: this.setState is not a function at FileReader.reader.onload

Component

import React, { Component, PropTypes } from 'react'
import { Link, browserHistory } from 'react-router'
import { connect } from 'react-redux'
import Cropper from 'react-cropper';

class HeadPortrait extends Component {
  constructor(props) {
    super(props)
    this.state = {
      image: '',
    }
  }

  clickadd(e) {
    document.getElementById('uploadfiles').click();
  }

  loadFile(e) {
    e.preventDefault();
    var reader = new FileReader();
    reader.onload = function () {
      this.setState({ image: reader.result })
    };
    reader.readAsDataURL(e.target.files[0]);
    ;
  };

  _crop() {
    // image in dataUrl
    console.log(this.refs.cropper.getCroppedCanvas().toDataURL());
  }

  render() {
    return (
      <div className="group-content width415">
        <input id="uploadfiles" type="file" accept="image/*" onChange={this.loadFile.bind(this)}></input>
        <a onClick={this.clickadd.bind(this)} className="gt-btn-small gt-left ">Add Image</a>
        <div>
          <div className="bigImageprev gt-left"><img width="300" height="300" id="output" /></div>
        </div>
        <div className="gt-clear"></div>
        <div className="btnSaveImage gt-right"><a className="gt-btn-small" href="#">Save</a></div>

        <Cropper
          ref='cropper'
          src={this.state.image}
          style={{ height: 400, width: '100%' }}
          // Cropper.js options
          aspectRatio={16 / 9}
          guides={false}
          crop={this._crop.bind(this)} />
      </div>
    )
  }
}

function mapStateToProps(state) {
  return {
    // stories: state.stories
  }
}

export default connect(mapStateToProps)(HeadPortrait)

Trying do like in example https://github.com/roadmanfong/react-cropper/blob/master/example/src/Demo.jsx

2

2 Answers 2

15

Problem is the function you are using for onload: this there is not your classes this. Try either an arrow function:

reader.onload = () => this.setState({ image: reader.result })

Or assign this to a variable before

const scope = this
reader.onload = function () {
  scope.setState({ image: reader.result })
}

Also it is worth binding the event handlers in the constructor rather than directly in render, because this way you'll re-render your component no matter how your state changes - since the event handler is a new reference each time:

constructor(props) {
  super(props)
  this.state = {
    image: '',
  } 
  this.loadFile = this.loadFile.bind(this) // properly bound once
}

In render:

<input onChange={this.loadFile}></input>
Sign up to request clarification or add additional context in comments.

Comments

0

The reader.onload function needs to be bound to this. Then it will have this.setState on scope.

var onloader = function(){this.setState({ image: reader.result }); reader.onload = onloader.bind(this);

You can also just use an arrow function:

reader.onload = ()=>{this.setState({ image: reader.result });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.