the code is to fetch data from an API and feel free to state any possible improvement
i made a button to provoke fetch function and input field to read the value from but just for trial purposes i made the value fixed in the code but the onClick function gets invoked on first render without pressing anything ,if someone could elaborate plz.
class App extends React.Component {
fetcher = async(userName)=>{
debugger; // debugger1
const resp = await fetch(ApiBaseUrl+userName);
try{
debugger; // debugger 2
const data = await resp.json();
return data;
}
catch(error){
return "error"
}
}
show = (inputValue) =>
{
this.fetcher(inputValue);
// this.setState({infoHolder: {name:'hossam',age:32}});
debugger; // debugger 3
}
render(){
debugger; // debugger 4
return(
<>
<label>Please enter the name of the profile you would like to show information for :</label>
<br></br>
<input type='text' id = 'UIForProfile'></input>
<br></br>
<button onClick={this.show('input')}>Fetch</button>
</>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
and another question :-
the sequence of debuggers executions is as follows : debugger 4 -> debugger1 -> debugger 3 -> debugger 2. why did debugger 3 came before debugger 2 'why did the compiler leave the fetcher function and got back to it and why did the function get invoked when i didn't press the button yet.
You're calling the function directly, instead of passing a function to be called when the button is clicked. You can use an arrow function for this like so:
<button onClick={() => this.show('input')}>Fetch</button>
Related
I have an application in react native where i'm developing a search feature like Instagram.
It is like if user stop typing show him his query result.
my current approach is messing up redux. And sometimes it returns same element multiple times or sometime random elements which are irrelevant of that query.
right now. I'm calling search api immediately as use start typing in searchbar.
here is code below of my component.
import { getSearchDataApi } from "../../api/search/search";
import { clearSearchData, setSearchData } from "../../redux/action/search";
const SearchScreen =(props)=>{
const [autoFocus,setAutoFocus] = useState(true)
const [keyWord,setKeyWord] = useState(null)
const [isLoading,setIsLoading] = useState(false)
const [isError,setIsError] = useState(false)
const [pageNumber,setPageNumber] = useState(1)
const [loadMore,setLoadMore] = useState(true)
const loadMoreDataFunc =()=>{
if (pageNumber <= props.totalSearchPage) {
setPageNumber(pageNumber+1)
}
else {
setLoadMore(false)
}
}
const searchData = async(keyWord)=>{
console.log(keyWord,pageNumber)
try {
setIsLoading(true)
var searchResponse = await getSearchDataApi(keyWord,pageNumber)
props.setSearchData(searchResponse.data)
setIsLoading(false)
}
catch (e) {
setIsError(true)
console.log("Error --- ", e.response.data.message)
showMessage({
message: e.response.data.message,
type: "danger",
});
}
}
return (
<View>
....
</View>
)
}
const mapStateToProps = (state)=>({
searchData: state.searchReducer.searchData,
totalSearchPage: state.searchReducer.totalSearchPage,
})
export default connect(mapStateToProps,{setSearchData,clearSearchData})(SearchScreen);
I will really every thankful to someone how can help me in fixing. Appreciation in advance!
GOAL :
The goal that i want to achieve is when user stop typing then i call searchAPI with the keyword he/she entered in searchBar that's all.
I have also tried setTimeOut but that made things more worse.
The best solution to your problem is to debounce the state variable that is responsible for the user input. This way, you can use the effect hook to watch for changes on the debounced variable, and call the search API if/when conditions for the search API variables are met.
Well, I have put some effort to solve it with setTimeout once again and i have done it by following code of snippet.
useEffect(()=>{
setPageNumber(1)
props.clearSearchData()
const delayDebounceFn = setTimeout(() => {
console.log(keyWord)
if (keyWord) {
searchData(keyWord)
}
}, 500)
return () => clearTimeout(delayDebounceFn)
},[keyWord])
You can use a setInterval to create a countDown starting from 2 to 0, or 3 to 0, put it a state.
whenever user types, onChange is called, the from the callback you reset the countDown.
using useEffect with the countDown as dependency, you can open the search result whenever the countdown reaches 0. (which means the user hasn't typed anything since 2s ago)
this might help for creating the countdown https://blog.greenroots.info/how-to-create-a-countdown-timer-using-react-hooks
I have a react async select component. This component has a loadOptions props, where you need to pass a function to load data. At the moment it looks like this
const MyComponent = () => {
const [positionId, setPositionId] = useEffect('');
return (
{
positionId &&
<AsyncSelect
loadOptions={(search, prevOptions, additional) => loadMyOptions(search, prevOptions, additional, positionId)}
(...other props)
/>
}
<Input
value={positionId}
onChange={(e) => setPositionId(e.target.value)}
/>
)
}
The loadMyOptions function describes the data loading logic. This function takes the last parameter, positionId, which changes depending on what was entered in the input field. Now if you enter a value in the input field, then AsyncSelect appears and it loads the necessary options. But if after that you enter something else in input and change the positionId, and try to load new data into AsyncSelect, then it doesn't send a request to the backend with the new positionId value.
I tried to wrap the function in useCallback
const loadNewOptions = useCallback(
(search, prevOptions, additional) => {
return loadMyOptions(search, prevOptions, additional, positionId);
},
[positionId]
);
But it did not help. Please tell me how to make it so that when changing positionId and clicking on AsyncSelect, a request with a new value of positionId goes to the backend?
It seems that there's a race condition somewhere in your code, but you don't have to use the "outer" positionId, instead use the one that you pass instead:
const loadNewOptions = useCallback((search, prevOptions, additional, posId) => {
return loadMyOptions(search, prevOptions, additional, posId)
}, [])
Thanks for checking this post.
I'm new to React and I have a question about fetching data before opening a modal.
I have a card list and when I click on a card, a modal pops up with the data of clicked item (handleModal function takes id of clicked item). And I want the data inside already without delay every time the modal pops up.
const [eachUser, setEachUser] = useState({});
const [isModalOn, setIsModalOn] = useState(false);
const loadDetailInfo = async id => {
if (isModalOn) {
return;
}
await axios
.get(`${API}/api/users/${id}`)
.then(res => setEachUser(res.data.data))
.catch(err => console.log(err));
};
const handleModal = id => {
if (!isModalOn) {
setEachUser('');
}
loadDetailInfo(id);
setIsModalOn(!isModalOn);
};
return (
<>
<CardList data={filteredUser} handleModal={handleModal} />
{isModalOn && <Modal data={eachUser} handleModal={handleModal}/>}
</>
);
But with this code, since it takes time to fetch data from the API, modal shows blank view at first and I don't know how to fix this.
I've tried useEffect and putting the loadDetailInfo function inside with the id state in a dependency array but I couldn't fix it for some reason..
It would be really appreciate if you give me some advice.Thank you for your time and advice in advance.
I've been trying to build a random quote app. So far I have this: https://codesandbox.io/s/nice-heyrovsky-4msq4?file=/src/App.js
In short, I fetch a quotes list from an API, and then try to display the quotes and the authors when the page loads, and every time I press the button. But there's a problem.
export default function App() {
useEffect(() => {
fetch(
"https://gist.githubusercontent.com/natebass/b0a548425a73bdf8ea5c618149fe1fce/raw/f4231cd5961f026264bb6bb3a6c41671b044f1f4/quotes.json"
)
.then((data) => data.json())
.then((quotes) => setAllQuotes(quotes));
}, []);
const [allQuotes, setAllQuotes] = useState([]);
// this is the array of all quote objects
const [quoteIndex, setQuoteIndex] = useState(0);
//this is the number used as array index
const [text, setText] = useState("This app is Broken");
// this is the quote text to be displayed
const [author, setAuthor] = useState("Press set twice");
// this is the quote author to be displayed
const [chosenQuote, setChosenQuote] = useState({});
// this is the selected quote object
function randomNumber() {
return Math.floor(Math.random() * allQuotes.length);
}
let handleClick = () => {
setQuoteIndex(randomNumber);
setText(chosenQuote.quote);
setAuthor(chosenQuote.author);
setChosenQuote(allQuotes[quoteIndex]);
// this is supposed to choose a random object within the array, and set text and quote state to the quote and author properties of the selected object
};
console.log(chosenQuote);
return (
<div id="quote-container">
<div id="quote-box">
<h1 id="text">{text}</h1>
<p id="author">{author}</p>
{/*when I press the button, it loads the next quote, but displays the previous quote, hence why nothing displays on first click */}
<button onClick={handleClick}>New Quote</button>
</div>
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
If I try to load the quotes while the page loads, it gives me the "Cannot read property(quote) of undefined" error. If I try to load the quotes after the page has loaded by editing the javascript, then it works, but it displays the messages from the previously loaded object, not the current one. You can see the behavior in codesandbox.
So, can someone explain to me why this is happening and how I can fix it so that the app displays the quotes properly on load and then changes on click?
this is because setState from useState hook is asynchronous so you can do something like:
setChosenQuote(allQuotes[quoteIndex]);
setText(allQuotes[quoteIndex].quote);
setAuthor(allQuotes[quoteIndex].author);
How to call every backspace remove call load option. I am using select.Async control in every input change method call fetch method and fetch data but when I press backspace then first time called that load option method but in next time that can't call load option method.
getUsers = (input) => {
console.log(input);
if (!input) {
return Promise.resolve({ options: [] });
}
if (input.length > 2) {
const newstate = this.state;
newstate.loadingtext = 'Searching...';
this.setState({ newstate });
const searchLocation = Object.assign({}, cookie.load('cLocation'));
searchLocation.searchText = input;
searchLocation.isBusiness = false;
console.log(input.toString().length);
return fetch(sourceName.searchNavbar, apiUrl.locationAndBusiness,
searchLocation)
.then(json => ({ options: json.data }));
}
return null;
}
<Select.Async
onChange={this.onChange}
valueKey="placeID"
filterOptions={this.filterOptions}
labelKey="cityState"
loadOptions={this.getUsers}
onInputChange={inp => this.onInputChange(inp)}
onBlur={this.onBlur}
onInputKeyDown={inp => this.onInputKeyDown(inp)}
onFocus={this.onFocousSearch}
value={this.state.value}
searchPromptText="Please enter 3 or more characters"
loadingPlaceholder={this.state.loadingtext}
noResultsText="No results found"
options={this.state.options}
placeholder={this.state.placeholdervalue}
autoBlur
/>
In above code in load option that get user method call. My get User method is :
When I click first time back space then get user method call but in second time I pressed back space then not called that get user method. How to call every backspace remove call this method.
solved my self using cache property in react-select-plus plugin. give that false like this cache={false}. so every time call getuser() method.