I have a page which allows a user to submit a url from which data is scraped. The user is subsequently presented with the filtered data.
Because the scraping takes some time I would like to implement a loader. While the loader class will (hopefully) be relatively straight forward, it's the state for loading
which I'm having issues with. The state itself is never updated. Although other state values are such as setFilters
.
const [searchState, setSearchState] = useState({
searchCriteria: "https://en.wikipedia.org/wiki/2020_Central_Vietnam_floods",
headers:[],
references: []
});
const [filterState, setFilters] = useState({
languageFilter: ""
});
const [loadingState, setLoadingState] = useState({
loading: false
});
The above are all passed into Search
with a context
<>
<SearchContext.Provider value={{searchState, setSearchState,filterState, setFilters, loadingState, setLoadingState}} >
<Search />
<DonateButton />
<WikiHeaderGroup />
</SearchContext.Provider>
</>
And then I have a handleSubmit
inside the Search
component.
import React, {useContext} from "react";
import {SearchContext} from "../../contexts/SearchContext"
import "../../App.css"
export function Search (){
const {searchState, setSearchState, filterState, setFilters, loadingState, setLoadingState} = useContext(SearchContext);
const handleSubmit = (event) => {
setFilters({languageFilter:""})
setLoadingState({loading:true})
console.log("Loading State : " + loadingState.loading)
event.preventDefault();
event.persist(); //persists the event object into the function
const fetchReferences = async () => {
fetch('http://127.0.0.1:8080/search/', {
method: 'POST',
body: JSON.stringify({
url: searchState.searchCriteria
}),
headers: {"Content-type": "application/json; charset=UTF-8"}
}).then(response => {
console.log(response)
return response.json()
}).then(json => {
console.log(json)
setSearchState({
headers:json.headers,
references:json.references
})
setLoadingState({loading:false})
console.log("Loading State : " + loadingState.loading)
});}
fetchReferences();
}
return (
<div className="search container">
<div className="input-group input-group-sm mb-3 center">
<div className="input-group-prepend">
<span className="input-group-text" id="inputGroup-sizing-sm">Wikipedia URL:</span>
</div>
<form onSubmit={(event) => handleSubmit(event)}>
<input
type="text"
id="searchBox"
className="form-control center"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-sm"
value={searchState.searchCriteria}
onChange={(event) => setSearchState({searchCriteria:event.target.value, resultId:0})}
placeholder="Add a url" />
</form>
</div>
</div>
);
}
export default Search;
don't use object for booleans, just
const [loadingState, setLoadingState] = useState(false);
....
setLoadingState(true)
btw looks like a closure problem. you see loadingState always false cause the closure. take a look at this Be Aware of Stale Closures when Using React Hooks
A way to solve it is using refs
const loadingStateRef = useRef(loadingState);
//then inside the function u can access
latestValue.current