问题
I have a simple file upload utility, for which I am using react-dropzone, and in conjunction to that I wanted to use material-ui LinearProgress bar to show the progress.
Shown below is the component I created which renders the file upload utility along with the LinearProgress bar.
I am using superagent library for the actual upload of the back to the backend using multipart formdata. The superagent's request allows a callback or an event handler for upload progress. In my code, the progress event handler gets successfully called and is proved by the console.log statements. On each progress call, I update the this.state.completed attribute which is used by the LinearProgress bar.
The problem is the progress bar does not move forward. I am definitely missing something very simple.
Any help is much appreciated and thank you in adavance.
import React, {Component} from 'react';
import Dropzone from 'react-dropzone';
import request from 'superagent';
import LinearProgress from 'material-ui/LinearProgress';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
export default class MultiFileUpload extends Component {
constructor(props) {
super(props);
this.state = {
completed: 0,
};
}
onDrop(files) {
console.log('Received files: ', files);
this.state.completed = 0;
var data = new FormData();
var req = request.post('/nltools/v1/files/upload');
files.forEach((file)=> {
data.append('files[]', file, file.name);
});
req.on('progress', (p) => {
console.log('Last percentage', this.state.completed);
var percent = Math.floor(p.percent);
if (percent >= 100) {
this.setState({completed: 100});
console.log('Done 100%');
} else {
this.setState({completed: percent});
this.state.completed = percent;
console.log('Percentage done: ', percent);
}
});
req.send(data);
req.end(function(err, res){
this.state.completed = 0;
console.log("Successfully uploaded");
});
}
render() {
var thisStyle = {
borderWidth: 4,
borderColor: "orange",
borderStyle: "dashed",
borderRadius: 4,
margin: 30,
padding: 30,
height: 300,
transition: "all 0.5s"
};
var progressStyle = {
margin: 30,
passing: 30,
};
return (
<div>
<div style={progressStyle}>
<MuiThemeProvider>
<LinearProgress color="orange" mode="determinate" value={this.state.completed} />
</MuiThemeProvider>
</div>
<Dropzone onDrop={this.onDrop} className="dropzone-box" style={thisStyle}>
<div>Try dropping some files here, or click to select files to upload. {this.state.completed}</div>
</Dropzone>
</div>
);
}
}
回答1:
Firstly, I think your problem might be this:
onDrop={this.onDrop}
should be
onDrop={files => this.onDrop(files)}
or...
onDrop={this.onDrop.bind(this)}
or...
constructor(props) {
super(props);
this.state = {
completed: 0,
};
this.onDropHandler = this.onDrop.bind(this);
}
// ... then on your component:
onDrop={this.onDropHandler}
...otherwise, all your "this" references inside of onDrop() won't be correct, so "this.state" and "this.setState" would fail.
But also, you should never mutate your state directly. Always use setState(). So, remove all calls like this:
this.state.completed = ???;
always do this instead:
this.setState({ completed: ??? });
Also, setState is asynchronous. So, if you need to have something fired only after the state has been updated, you can pass a callback function as the 2nd argument:
this.setState({ completed: 75 }, () => { console.log('state.completed is now 75'));
// ^^ Immediately after the above call state.completed is probably not 75 yet,
// because setState() is async
Lastly, pay particular attention to your req.end() call. In there, you are only mutating the state (again, that's bad) and you are not calling .setState() at all (hence, the component won't be re-rendered after req.end() )
回答2:
Complete example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import Dropzone from "react-dropzone";
import request from "superagent";
import { Line } from 'rc-progress';
class App extends Component {
state = {
completed: 0
}
onDrop = files => {
this.setState({ completed: 0 });
var data = new FormData();
files.forEach(file => {
data.append("files[]", file, file.name);
});
var req = request.post("http://localhost:3001");
req.on('progress', event => {
var percent = Math.floor(event.percent);
if (percent >= 100) {
this.setState({ completed: 100 });
} else {
this.setState({ completed: percent });
}
});
const that = this;
req.send(data);
req.end((err, res) => {
console.log("Successfully uploaded");
});
};
render() {
const divStyle = {
border: '1px solid black'
};
return (
<div style={divStyle}>
<Dropzone onDrop={this.onDrop} className="dropzone-box">
<div>Try dropping some files here, or click to select files to upload. {this.state.completed}</div>
<Line percent={this.state.completed} strokeWidth="0.5" strokeColor="#2db7f5" strokeLinecap="square" />
</Dropzone>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
来源:https://stackoverflow.com/questions/40476405/material-ui-linearprogress-bar-not-working