Reputation: 1014
Im just wondering how i can stop the function from returning before the state has been updated - Here is my code so i can explain more clearly.
const mockData = {
current: {
temperature: 'loading'
}
}
export default function Weather({ city }) {
const [data, setData] = useState(mockData)
const url = `http://api.weatherstack.com/current?access_key=2cbe1b14f771abee0713f93317e1b107&query=${city}`
useEffect(() => {
axios.get(url).then(({ data }) => {
setData(data, () => { })
})
}, [])
return (
<div>
<h1>Weather</h1>
<p>temperature: {data.current.temperature}</p>
</div>
)
}
Right now i am using mockData because if i dont i will get an error because the .current.temperature properties do not exist (because set state hasnt been updated yet). How can i stop the error and stop the div being returned before the set state has been updated or atleast stop the error and return an empy div or something.
Upvotes: 1
Views: 37
Reputation: 900
You need to check that data
exists before you reference data.current
, and you need to check that data.current
exists before you reference data.current.temperature
. If you access a property of undefined
, your code will crash.
You need to have some additional state, such as isLoading
If you want a hack, you can do this:
export default function Weather({ city }) {
const [data, setData] = useState(mockData)
const url = `http://api.weatherstack.com/current?access_key=2cbe1b14f771abee0713f93317e1b107&query=${city}`
useEffect(() => {
axios.get(url).then(({ data }) => {
setData(data, () => { })
})
}, [])
function renderTemperature() {
if (!data) {
return null;
} else if (data && !data.current) {
return null;
} else if (data.current && data.current.temperature) {
return <p>temperature: {data.current.temperature}</p>
}
}
return (
<div>
<h1>Weather</h1>
{ renderTemperature() }
</div>
)
}
Much better solution:
export default function Weather({ city }) {
const [data, setData] = useState(null)
const [isLoaded, setIsLoaded] = useState(false);
const url = `http://api.weatherstack.com/current?access_key=2cbe1b14f771abee0713f93317e1b107&query=${city}`
useEffect(() => {
axios.get(url).then(({ data }) => {
setData(data, () => { })
setIsLoaded(true);
})
}, [])
function renderTemperature() {
}
return (
<div>
<h1>Weather</h1>
{ isLoaded ? <p>temperature: {data.current.temperature}</p> : null}
</div>
)
}
Upvotes: 0
Reputation: 1035
What you can do is add a conditional within your return.
Try this:
return (
<div>
<h1>Weather</h1>
<p>Temperature: {(data && data.current) ? data.current.temperature : ""}</p>
</div>
)
You can also use optional chaining to achieve the same result.
return (
<div>
<h1>Weather</h1>
<p>Temperature: {data?.current?.temperature || ""}</p>
</div>
)
Upvotes: 1