React.js oändlig loop när jag försöker använda setState och handleImage körs 4 ggr.

Trädvy Permalänk
Medlem
Registrerad
Jul 2016

React.js oändlig loop när jag försöker använda setState och handleImage körs 4 ggr.

Hej!

Jag har ett formulär där jag vill hämta en bild och sedan ladda ner den i en databas ihop med övriga data och samtidigt spara filen i en viss katalog på hårddisken.

Men när jag hämtar bilden så körs handleImage() 4 gånger och vid sista gången den körs så försvinner det data jag har hämtat och ersätts med endast imagePreviewUrl.

Så här ser console.logen ut när jag hämtar en bild.

Sell.js 67 {picture: "C:\fakepath\klubba.jpg", file: "", imagePreviewUrl: ""}
Sell.js:74 C:\fakepath\klubba.jpg
Sell.js:67
Sell.js:74 undefined
Sell.js:67 {picture: "C:\fakepath\klubba.jpg", file: File(2991), imagePreviewUrl: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD…AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//Z"}
Sell.js:74 C:\fakepath\klubba.jpg
Sell.js:67 data:image/jpeg;base64,/9j/4AAQSkZfWNr2P1Wd+aTVNP+7UX8zbgVvUy+K3ljFZdpvJcslx4LLKcZfi4eKX9qV38zKgFbd8pAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//Z
Sell.js:74 undefined

Jag skulle även vilja använda mig av picture: "C:\fakepath\klubba.jpg" men när jag använder mig av setState så blir det en evighetsloop.

Vad har jag gjort för fel??

import React, { Component } from 'react'; import Ocean from './../images/ocean.jpg'; //import ReactFileReader from 'react-file-reader'; import Price from './Price'; import UploadImage from './UploadImage'; import './Sell.css'; class Sell extends Component { constructor(props) { super(props); this.state = { sport: "", title: "", text: "", price: "", picture: "", pictureName: "", name: "", email: "", phone: "", municipality: "", county: "", value: "", }; this.handleSubmit = this.handleSubmit.bind(this); this.handleSport = this.handleSport.bind(this); this.handleCounty = this.handleCounty.bind(this); this.handleChange = this.handleChange.bind(this); this.handleImage = this.handleImage.bind(this); } update() { this.setState({ sport: this.refs.sport.value, title: this.refs.title.value, text: this.refs.text.value, price: this.refs.price.value, picture: this.refs.picture.value, name: this.refs.name.value, email: this.refs.email.value, phone: this.refs.phone.value, municipality: this.refs.municipality.value, county: this.refs.county.value }) } handleSport(event) { this.setState({sport: event.target.value}); } handleCounty(event) { this.setState({county: event.target.value}); } handleImage(picture) { console.log(picture); const data = picture; let key = 'picture'; console.log(picture[key]); let image = picture[key]; this.setState({picture: image}); } handleSubmit(event) { event.preventDefault(); const image = this.refs.picture.value.split('C:\\fakepath\\')[1]; const data = { sport: this.refs.sport.value, title: this.refs.title.value, text: this.refs.text.value, price: this.refs.price.value, picture: image, //picture: event.target.result, name: this.refs.name.value, email: this.refs.email.value, phone: this.refs.phone.value, municipality: this.refs.municipality.value, county: this.refs.county.value } console.log(data); fetch('http://localhost/reusesport/src/api/newadvertisment.php', { method: 'POST', body: JSON.stringify(data) }) .then(resp => resp.text()) .then(data => console.log(data)) .then(resp=>console.warn("result", resp)) } handleChange(event) { console.log('handleChange'); } onSubmit = () => { } render() { return ( <div className="Sell"> <div className="Sell-picture"> <div className="Sell-pictureimg"><img src={Ocean} alt="Reusesports" /></div> <div className="Sell-Box"> <div className="Sell-innerbox"> <h1 className="Sell-title">Har du begagnad sportutrustning som inte används?</h1> <h2 className="Sell-intro">Sälj den hos oss, det finns många som gärna vill köpa dem.</h2> <form className="Sell-form" onSubmit={this.handleSubmit}> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Välj sport</div> <select className="Sell- Sell-input" id="sport" name="sport" ref="sport" onChange={this.handleChange} onChange={this.handleSport} value={this.state.sport} required> <option value="Badminton">Badminton</option> <option value="Bandy">Bandy</option> <option value="Basket">Basket</option> <option value="Boxning">Boxning</option> <option value="Brottning">Brottning</option> <option value="Bågskytte">Bågskytte</option> <option value="Cykelsport">Cykelsport</option> <option value="Flygsport">Flygsport</option> <option value="Fotboll">Fotboll</option> <option value="Friidrott">Friidrott</option> <option value="Dykning">Dykning</option> <option value="Fäktning">Fäktning</option> <option value="Golf">Golf</option> <option value="Gymnastik">Gymnastik</option> <option value="Handboll">Handboll</option> <option value="Ishockey">Ishockey</option> <option value="Innebandy">Innebandy</option> <option value="Lacrosse">Lacrosse</option> <option value="Kampsport">Kampsport</option> <option value="Kanot">Kanot</option> <option value="Klättring">Klättring</option> <option value="Konståkning">Konståkning</option> <option value="Motorsport">Motorsport</option> <option value="Tennis">Tennis</option> <option value="Ridsport">Ridport</option> <option value="Rugby">Rugby</option> <option value="Segling">Segling</option> <option value="Skidsport">Skidsport</option> <option value="Vattenskidor">Vattenskidor</option> <option value="Vindsurfing">Vindsurfing</option> <option value="Övriga">Övriga</option> </select> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ange titel</div> <input className="Sell-input" id="title" name="title" maxLength="30" type="text" ref="title" onChange={this.handleChange} onChange={this.update.bind(this)} required /> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ange en bra beskrivning av produkten</div> <textarea className="Sell-input Sell-text" rows="4" cols="50" maxLength="500" name="text" id="text" type="text" ref="text" onChange={this.handleChange} onChange={this.update.bind(this)} required /> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title">Ange pris</div> <input className="Sell-price Sell-input" id="price" name="price" type="text" ref="price" onChange={this.handleChange} onChange={this.update.bind(this)} required/> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ladda upp bilder</div>+ <UploadImage picture={this.handleImage} ref="picture" id="picture" name="picture" onChange={this.update.bind(this)} /> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title">Ange ditt namn</div> <input className="Sell-name Sell-input" id="name" name="name" type="text" ref="name" onChange={this.handleChange} onChange={this.update.bind(this)} required/> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ange din mailadress</div> <input className="Sell-mail Sell-input" id="email" name="email" type="text" ref="email" onChange={this.handleChange} onChange={this.update.bind(this)} required/> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ange det telefonnummer du vill köparna ska nå dig på</div> <input className="Sell-mail Sell-input" id="phone" name="phone" type="text" ref="phone" onChange={this.handleChange} onChange={this.update.bind(this)} required/> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Ange kommun</div> <input className="Sell-municipality Sell-input" id="municipality" name="municipality" type="text" ref="municipality" onChange={this.handleChange} onChange={this.update.bind(this)} required/> </div> <div className="Sell-innerBox"> <div className="Sell-sport Sell-input_title ">Vilket län bor du i</div> <select className="Sell-county Sell-input" id="county" name="county" ref="county" onChange={this.handleChange} onChange={this.handleCounty} value={this.state.county}> <option value="blekinge">Blekinge</option> <option value="Dalarna">Dalarna</option> <option value="Gotland">Gotland</option> <option value="Gävleborg">Gävleborg</option> <option value="Halland">Halland</option> <option value="Jämtland">Jämtland</option> <option value="Jonkoping">Jönköping</option> <option value="Kalmar">Kalmar</option> <option value="Kronoberg">Kronoberg</option> <option value="norrbotten">Norrbotten</option> <option value="Skåne">Skåne</option> <option value="Stockholm">Stockholm</option> <option value="Södermanland">Södermanland</option> <option value="Uppsala">Uppsala</option> <option value="Värmland">Värmland</option> <option value="Västerbotten">Västerbotten</option> <option value="Västernorrland">Västernorrland</option> <option value="vastermanland">Västermanland</option> <option value="Västragötaland">Västra Götaland</option> <option value="Örebro">Örebro</option> <option value="Östergötland">Östergötland</option> </select> </div> <div className="Sell-innerBox"> <input className="Sell-submit" id="sub" type="submit" value="Lägg upp annonsen" /> </div> </form> </div> </div> </div> <Price price={this.state.price}/> </div> ); } } export default Sell;

import React, { Component } from 'react'; import "./UploadImage.css"; class UploadImage extends Component { constructor(props) { super(props); this.state = { picture: '', file: '', imagePreviewUrl: '' }; this.loadPicture = this.loadPicture.bind(this); } loadPicture(e) { e.preventDefault(); const {file} = this.state; const {onSubmit} = this.props; onSubmit(file); } handleImageChange(e) { e.preventDefault(); let reader = new FileReader(); let file = e.target.files[0]; reader.onloadend = () => { this.setState({ file: file, imagePreviewUrl: reader.result }); } this.setState({picture: this.refs.picture.value}); reader.readAsDataURL(file) } render() { let {imagePreviewUrl} = this.state; this.props.picture(this.state); let $imagePreview = null; if (imagePreviewUrl) { $imagePreview = (<img src={imagePreviewUrl} />); } else { $imagePreview = (<div className="previewText">Please select an Image for Preview</div>); } return ( <div> <form onSubmit={this.loadPicture}> <input className="fileInput" type="file" id="picture" name="picture" ref="picture" value={this.state.picture} picture={this.props.picture(this.state.imagePreviewUrl)} multiple accept=".jpg, .jpeg, .png" onChange={(e)=>this.handleImageChange(e)} required/> </form> <div className="imgPreview"> {$imagePreview} </div> </div> ) } } export default UploadImage;

Trädvy Permalänk
Medlem
Plats
Sverige
Registrerad
Jul 2001

Nu har jag inte någon tid att kolla igenom din kod så noga just nu tyvärr, men när sånt här händer: Kolla igenom din kod så att du inte anropar this.setState(...) i metoder som anropas i dina render()-metoder. Det kan skapa evighetsloopar, eftersom du då åter igen triggar en omrendering och sen samma sak gång på gång.
Kolla även så att du inte anropar this.SetState väldigt nära inpå varandra där du pillar på samma objekt i ditt state. setState är asynkron och du kan inte räkna med att det du försöker förändra / lägga till / uppdatera faktiskt har slått igenom när du gör nästa setState. Om du är beroende av ditt förra state skriver du istället:
this.setState((prevState, props) => ({items: value, ...prevState.items})) t.ex.

Andra saker du bör kolla igenom, som inte är relaterat till problemet är att inte binda metoder till this i dina render-metoder. Såg att du hade några onChange där du gör detta, vilket är prestandasänkande att för varje omrendering binda om. Gör istället detta i konstruktorn för klassen, som du gjort för andra delar av din kod.

Får se om jag hinner kolla mer på din kod och se vad som orsakar dina omrenderingar och överskrivning av ditt state senare sen, hinner tyvärr inte mer just nu.

WS: AMD Ryzen 7 1700 | 16 GB DDR4 | Geforce GTX 1060 OC 6GB | 480 + 256 + 240 + 240 GB SSD | Win10 x64 Professional + Antergos Linux (Arch-derivat)
Bärbar: Macbook Pro Retina 13" | Intel Core I5 2,4Ghz | 16GB RAM | 256GB Flash
Server: 3x HP Proliant microserver Gen8 | 16 GB DDR3 ECC ram | Sammanlagt 26TB HDD | Esxi