Search Results Disappearing - reactjs

When using React Bootstrap Typeahead's async typeahead, I get my search results, but then they very quickly disappear as soon as they appear, not allowing me to click on any of the search results. Here is my code:
const [searchOptions, setSearchOptions] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const filterBy = () => true;
const handleChange = (event) => {
console.log(event);
};
const handleSearch = async (query) => {
setIsLoading(true);
const results = await AdmiralService.searchByVendorIdOrTwitchName(query);
console.log(results.data);
setSearchOptions(results.data);
setIsLoading(false);
};
<AsyncTypeahead
filterBy={filterBy}
id="async-example"
labelKey={(option) => `${option.uid} - ${option.Name}`}
isLoading={isLoading}
minLength={3}
onSearch={handleSearch}
options={searchOptions}
onChange={handleChange}
placeholder="Search by VendorID/Username/Legal Name"
renderMenuItemChildren={(option, props) => (
<Fragment>
<div>{option.Name} - {option.uid}</div>
</Fragment>
)}
/>
I can see the results populate for just a second or so, and then they disappear.

Related

Returning 0 when transforming string information inside a useState into parseFloat [duplicate]

This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 6 months ago.
import * as C from './styles';
import AddButton from '../../components/AddButton';
import { useEffect, useState } from 'react';
import { useApi } from '../../hooks/useApi';
const AddProduct = () => {
const api = useApi();
const [apiCategories, setApiCategories] = useState<any[]>([]);
const [isCreate, setIsCreate] = useState<boolean>(false);
const [name, setName] = useState<string>('');
const [price, setPrice] = useState<number>(0);
const [desc, setDesc] = useState<string>('');
const [stock, setStock] = useState<number>(0);
const [categories, setCategories] = useState<string>('');
const [priceSTR, setPriceSTR] = useState<string>('');
const [stockSTR, setStockSTR] = useState<string>('');
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<boolean>(false);
useEffect(() => {
const category = async () => {
const categories = await api.getCategories();
setApiCategories(categories);
}
category();
}, []);
const onSubmit = async () => {
try {
setLoading(true);
const priceFLT = parseFloat(priceSTR);
const stockINT = parseInt(stockSTR);
setPrice(priceFLT);
setStock(stockINT);
setLoading(false);
await api.postProduct(name, price, desc, stock, categories);
setIsCreate(true);
setError(false);
setName('');
setDesc('');
setPriceSTR('');
setStockSTR('');
} catch (err) {
setError(true);
console.log(err);
}
}
return (
<C.Container>
<C.Post>
<C.Input
placeholder='Product name'
value={name}
onChange={e => setName(e.target.value)}
/>
</C.Post>
<C.Post>
<C.Desc
placeholder='Simple desc...'
value={desc}
onChange={e => setDesc(e.target.value)}
/>
</C.Post>
<C.Post>
<C.Input
placeholder='Price'
value={priceSTR}
onChange={e => setPriceSTR(e.target.value)}
/>
</C.Post>
<C.Post>
<C.Input
placeholder='Stock'
value={stockSTR}
onChange={e => setStockSTR(e.target.value)}
/>
</C.Post>
<C.Post>
<C.Categories
onChange={(e) => setCategories(e.target.value)}
>
<option value="Todas categorias">Choose a category</option>
{apiCategories.map(category => {
return (
<option value={`${category.name}`}>{category.name}</option>
)
})}
</C.Categories>
</C.Post>
<C.Add>
<AddButton
children='Send'
type='submit'
onClick={onSubmit}
/>
</C.Add>
{isCreate ? (
<p id='check'>Product Created!</p>
) : null}
{error ? (
<p id='error'>Error!</p>
) : null}
</C.Container>
)
}
export default AddProduct
My real purpose is to get the information from these inputs and send it to the "useApi" hook to validate the registration of a new product. However, the "price" and "stock" states in the API must be sent as float and int respectively, but I would like to get the information in string to then transform to float and int, and then send it to the API. It's what I try to do with
const priceFLT = parseFloat(priceSTR);
const stockINT = parseInt(stockSTR);
setPrice(priceFLT);
setStock(stockINT);
I can ship, but the stock and price always ends up as "0". How can I solve this problem?
ps: I would like to get this information in string in the input to be able to use placeholder and to be able to use "." to set a price.
You don't actually need to update a state for price or stock to provide it to your api call
...
const priceFLT = parseFloat(priceSTR);
const stockINT = parseInt(stockSTR);
setLoading(false);
await api.postProduct(name, priceFLT, desc, stockINT, categories);
...
setPrice or setStock are asynchronous, so the update is not immediate, that is partially why you end up with 0 (the default value) when you try to immediately use price or stock variables (another more complex reason is due to the way useState and reference work, once updated the price variable inside the onSubmit that has been called is not the same as the price variable that has been updated)

persist state after page refresh in React using local storage

What I would like to happen is when displayBtn() is clicked for the items in localStorage to display.
In useEffect() there is localStorage.setItem("localValue", JSON.stringify(myLeads)) MyLeads is an array which holds leads const const [myLeads, setMyLeads] = useState([]); myLeads state is changed when the saveBtn() is clicked setMyLeads((prev) => [...prev, leadValue.inputVal]);
In DevTools > Applications, localStorage is being updated but when the page is refreshed localStorage is empty []. How do you make localStorage persist state after refresh? I came across this article and have applied the logic but it hasn't solved the issue. I know it is something I have done incorrectly.
import List from './components/List'
import { SaveBtn } from './components/Buttons';
function App() {
const [myLeads, setMyLeads] = useState([]);
const [leadValue, setLeadValue] = useState({
inputVal: "",
});
const [display, setDisplay] = useState(false);
const handleChange = (event) => {
const { name, value } = event.target;
setLeadValue((prev) => {
return {
...prev,
[name]: value,
};
});
};
const localStoredValue = JSON.parse(localStorage.getItem("localValue")) ;
const [localItems] = useState(localStoredValue || []);
useEffect(() => {
localStorage.setItem("localValue", JSON.stringify(myLeads));
}, [myLeads]);
const saveBtn = () => {
setMyLeads((prev) => [...prev, leadValue.inputVal]);
// setLocalItems((prevItems) => [...prevItems, leadValue.inputVal]);
setDisplay(false);
};
const displayBtn = () => {
setDisplay(true);
};
const displayLocalItems = localItems.map((item) => {
return <List key={item} val={item} />;
});
return (
<main>
<input
name="inputVal"
value={leadValue.inputVal}
type="text"
onChange={handleChange}
required
/>
<SaveBtn saveBtn={saveBtn} />
<button onClick={displayBtn}>Display Leads</button>
{display && <ul>{displayLocalItems}</ul>}
</main>
);
}
export default App;```
You've fallen into a classic React Hooks trap - because using useState() is so easy, you're actually overusing it.
If localStorage is your storage mechanism, then you don't need useState() for that AT ALL. You'll end up having a fight at some point between your two sources about what is "the right state".
All you need for your use-case is something to hold the text that feeds your controlled input component (I've called it leadText), and something to hold your display boolean:
const [leadText, setLeadText] = useState('')
const [display, setDisplay] = useState(false)
const localStoredValues = JSON.parse(window.localStorage.getItem('localValue') || '[]')
const handleChange = (event) => {
const { name, value } = event.target
setLeadText(value)
}
const saveBtn = () => {
const updatedArray = [...localStoredValues, leadText]
localStorage.setItem('localValue', JSON.stringify(updatedArray))
setDisplay(false)
}
const displayBtn = () => {
setDisplay(true)
}
const displayLocalItems = localStoredValues.map((item) => {
return <li key={item}>{item}</li>
})
return (
<main>
<input name="inputVal" value={leadText} type="text" onChange={handleChange} required />
<button onClick={saveBtn}> Save </button>
<button onClick={displayBtn}>Display Leads</button>
{display && <ul>{displayLocalItems}</ul>}
</main>
)

React - I have to click a button twice to display api data

I would like to display API data on a button click. My state is set to an empty array initially and I guess that's why it shows an empty array at first click, but what could I write differently to show data on first click ? After the initial click it works.
My code:
const Search = () => {
const [textInput, setTextInput] = useState('');
const [tickers, setTickers] = useState([]);
const [prices, setPrices] = useState([]);
const [isClicked, setIsClicked] = useState(false);
const inputHandler = (e) => {
setTextInput(e.target.value);
}
const showData = async (e) => {
e.preventDefault();
const url = `https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=${textInput}&apikey=${process.env.REACT_APP_ALPHA_VANTAGE_API_KEY}`
try {
const data = await axios.get(url);
if(data) {
setPrices([data.data['Monthly Time Series']['2021-11-30']]);
}
} catch(err) {
console.log(err)
}
console.log(prices);
setIsClicked(true);
setTextInput('');
}
return (
<StyledSearch>
<h1>Security Price Monitor App </h1>
<form onSubmit={submitSearch}>
<input type="text" value={textInput} onChange={inputHandler} placeholder='Enter Ticker'/>
<button type="submit" onClick={showData}>Search</button>
</form>
{isClicked &&
<Chart tickers = {tickers} setTickers={setTickers} prices={prices} setPrices={setPrices}/>
}
</StyledSearch>
)
}
Try to change your conditional rendering condition to:
{prices.length > 0 && (
<Chart
tickers={tickers}
setTickers={setTickers}
prices={prices}
setPrices={setPrices}
/>
)}
I think that you can remove the isClicked state. It is redundant.

Why the Search Function for Random user api is not working?

I'm working on random user api, the fetching of user name and pagination is working fine but not the search event. Please help.
I pushed my code on stackblitz, to help you guys to debug it easily.
here's the link: https://stackblitz.com/edit/search-and-pagination-in-react-by-react-hooks?file=src/App.js
below in image you can see that the name i mentioned in search box is present in api but its not comming on first place.
Working example in here.
const App = () => {
const [myApi, setMyApi] = useState([]);
const [data, setData] = useState([]); // add your data to here
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(10);
const [searchUser, setSearchUser] = useState("");
useEffect(() => {
fetch("https://randomuser.me/api/?results=50")
.then(data => data.json())
.then(json_result => {
setData(json_result.results); // set your data to state
let myApi = renderData(json_result.results); // render your component
setMyApi(myApi); // set it to state
});
}, []);
const renderData = (data) => {
return data.map((item, idx) => {
return (
<div key={idx}>
<img src={item.picture.thumbnail} alt="" /> {item.name.first}
<hr />
</div>
);
});
}
// get current post
const indexOfLastPost = currentPage * postsPerPage; // 1 * 10 = 10
const indexOfFirstPost = indexOfLastPost - postsPerPage; // 10 - 10 = 0
const currentPosts = myApi?.slice(indexOfFirstPost, indexOfLastPost); // 0 to 10
// search users by user input
const handleSearchInput = event => {
setSearchUser(event.target.value);
const newData = renderData(data.filter(item => item.name.first.toLowerCase().includes(event.target.value))); // render filtered data
setMyApi(newData); // and set it to state
};
const paginate = pageNumber => setCurrentPage(pageNumber);
return (
<div>
<Search onChange={handleSearchInput} />
<Pagination
postsPerPage={postsPerPage}
totalPosts={myApi?.length}
paginate={paginate}
/>
{currentPosts}
</div>
);
};
const Search = ({ onChange }) => {
return (
<div>
<input
type="text"
autoFocus={true}
placeholder="search users"
onChange={onChange}
/>
</div>
);
};
Since you're useEffect has [] (empty array) as the dependency, you're user fetching logic will only be called once i.e. on the initial rendering. You can add searchUser as useEffect's dependency so you can fetch users whenever the searchUser text changes.

react hooks issue when infinite paging filter applied

I have an infinite paging setup in a react redux project like this..
const ItemDashboard = () => {
const items= useSelector(state => state.items.items);
const dispatch = useDispatch();
const [loadedItems, setLoadedItems] = useState([]);
const [categories, setCategories] = useState([
'cycling',
'diy',
'electrical',
'food',
'motoring',
'travel'
]);
const initial = useRef(true);
const [loadingInitial, setLoadingInitial] = useState(true);
const [moreItems, setMoreItems] = useState([]);
const onChangeFilter = (category, show) => {
!show
? setCategories(categories.filter(c => c != category))
: setCategories([...categories, category]);
};
const loadItems = () => {
dispatch(getItems(categories, items && items[items.length - 1]))
.then(more => setMoreItems(more));
}
const getNextItems = () => {
loadItems();
};
useEffect(() => {
if(initial.current) {
loadItems();
setLoadingInitial(false);
initial.current = false;
}
}, [loadItems]);
useEffect(() => {
if(items) {
setLoadedItems(loadedItems => [...loadedItems, ...items]);
}
}, [items]);
useEffect(() => {
//this effect is fired on intial load which is a problem!
setLoadingInitial(true);
initial.current = true;
}, [categories]);
return (
<Container>
<Filter onFilter={onChangeFilter} categories={categories} />
{loadingInitial ? (
<Row>
<Col sm={8} className='mt-2'>
<LoadingComponent />
</Col>
</Row>
) : (
<ItemList
items={loadedItems}
getNextItems={getNextItems}
moreItems={moreItems}
/>
)}
</Container>
);
};
In the filter component, when the filter is changed the onChangeFilter handler method is fired which updates the array of categories in state. When this filter is changed I need to set the loadedItems in state to an empty array and call the load items callback again but I can't work out how to do it. If I add another effect hook with a dependency on categories state, it fires on the initial load also. I'm probably doing this all wrong as it feels a bit hacky the whole thing. Any advice much appreciated.

Resources