Reputation:
In my handleChange function I use an object spread to get all prior key/vals from this.state and I add on a new value to the selectedCountry key. My issue is that I keep reassigning the countryFlags value which messes up my app's state. Am I missing something? I've really wrestled with this for hours and I cannot figure out the reason for this. Is it my overall implementation of setState. Thank you in advance for your observation.
import React, {Component} from "react"
import FlagSelect from "./FlagSelect";
export default class FlagQuiz extends Component {
constructor() {
super()
this.state = {
countryFlags: undefined,
selectedCountry: ""
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount(){
fetch("https://restcountries.eu/rest/v2/all")
.then(function(response, reject) {
return response.json()
})
.catch(() => console.log("nope"))
.then((data) => {
this.setState({countryFlags: data})
});
}
handleChange(event){
event.preventDefault();
const {name, value, type, checked} = event.target
// console.log(this.state)
const newState = {...this.state}
newState.selectedCountry = value
// console.log(newState)
///STOP UPDATING THE countryFlgs!!
this.setState({...this.state, selectedCountry: value})
console.log(this.state)
}
render(){
const flagStyle = {
display: "block",
marginLeft: "auto",
marginRight: "auto",
width: "50%"
}
const src = this.state.countryFlags === undefined ? "" : this.state.countryFlags[0].flag
const buttonStye = {
background:"lightblue",
color: "white",
fontSize: "30px",
float: "right"
}
const countries = this.state.countryFlags ? [
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length)
] : ""
const fourCountries = () => {
let flagselects = countries ? countries.map((countrynum) =>{
return <FlagSelect
handleChange={this.handleChange}
checked={this.state.selectedCountry}
key={countrynum}
countryinfo={this.state.countryFlags[countrynum].name}/>
}) : null
return flagselects
}
return (
<div>
<form>
<div className="form-check">
{fourCountries()}
<div className="form-group">
<button style={buttonStye} >Guess</button>
</div>
</div>
</form>
<h1 style={{textAlign:"center"}}>Flag Quiz</h1>
<img src={src} alt="flag" style={flagStyle}
/>
{this.state.countryFlags ? console.log(this.state.countryFlags.length): ""}
</div>
)
}
}
My results are a selectedCountry but with a whole new set of randomized selection of countries from the countryFlags array.
Upvotes: 0
Views: 47
Reputation: 130112
Changing state is simple:
this.setState({ selectedCountry: value })
Nothing else is needed.
However, changing state will always cause a rerender. And I see a big problem with your rendering.
Everytime render
is called, you will randomize your flags:
const countries = this.state.countryFlags ? [
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length),
Math.floor(Math.random() * this.state.countryFlags.length)
] : ""
Therefore your UI will change.
Render
is supposed to always return the same thing if properties and state have not changed. However, your render
will always display different things depending on the random numbers.
You have to move your randomization to your state, for example:
.then((data) => {
const countries = [
Math.floor(Math.random() * data.length),
Math.floor(Math.random() * data.length),
Math.floor(Math.random() * data.length),
Math.floor(Math.random() * data.length)
]
this.setState({ countryFlags: data, countries })
});
Upvotes: 1