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

Permalänk

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;

Permalänk
Medlem

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.

Visa signatur

WS: Mac Studio M1 Max | 32 GB | 1TB | Mac OS
WS: Intel i5 12600K | 64 GB DDR4 @3600 Mhz | 2x1TB nvme 2x1TB SSD SATA | Windows 11 & Manjaro Linux
Bärbar: Macbook Pro 14" | M1 Pro | 16GB RAM | 512GB SSD | Mac OS
Servrar: Intel i7 10700K | 64 GB DDR4 @3600Mhz | 3 TB SSD + 22TB HDD | Unraid |
4x Raspberry pi 4b 8Gb | Dietpi |