Rendering React objects dynamically - javascript

My question is just about idea and creativity of you.
I have react component that is getting information from SQL database:
const [offers,setOffers] = useState([])
useEffect(()=>{
axios.get(`http://localhost:8085/incoming`)
.then(res=>{
setOffers(res.data.recordset)
})
.catch(error=>console.log(error))},[])
just when page is loaded.
In JSX I put one function that is filling my table:
<tbody className="table-hover">
{OfferItem(offers)}
</tbody>
The function is:
const OfferItem = (array)=>{
if(array!==undefined){
return array.map((item,index)=>{
return <IncomingOffer singleitem={item} index={index+1} key={item.Number}/>
})
}}
So far so good but I want to have input field that is providing dynamic search and re-rendering. So I put:
<label>Относно:</label><input onChange={searchAbout} />
And created my function:
const searchAbout = (e)=>{
e.preventDefault(e)
const string = e.target.value.toUpperCase()
const res = offers.filter(el=>Object.values(el).some(val=>val.toUpperCase().includes(string)))
setOffers(res)
}
In the way it is wrote it is working when typing in input field but as you see it is completely filtering the array and I am loosing all other items in it. So I was wondering for a way that I am filtering and re-rendering items but for example when I use backspace or remove the whole search criteria to see again my whole array information. I must admit I know how my code is working and what is expected but I do not know how to do it. Any ideas?

Related

Best practice for managing state of Array in React whilst providing back to back search functionality with filter

My question involves a number of components so I have tried to simplify.
I am trying to provide a a re-searchable menu in React. What I mean buy this is a user can search multiple times back to back. The issue is that I am using a single stateful array to search and present the results to the user. On the second search the stateful object has already been filtered and therefore the results are limited. I am tempted to have two copies of the array but is this best practice?
Further detail provided below:
The array is presented for user selection via a menu which drives the presentation of the remainder of the page.
The page component below has been simplified to contain on the elements relating to my question. It holds the GetData function which calls a post request to a server to retrieve the data destined for both the menu and the search.
The menu component shows the data and on selection sets the PreGameKey to the selected object id. This is then used to drive further functionality not included in the extract.
const PageComponent =()=>{
const authCtx = useContext(AuthContext);
const token = authCtx.token
const [preGameDataGroup, setPreGameDataGroup] = useState(null)
const [PreGameKey, setPreGameKey] = useState(null)
const [PreGameData, setPreGameData] = useState(null)
const GetData =()=>{
GetOppTrades(token,setPreGameDataGroup,setPreGameKey)
}
useEffect(GetData,[])
useEffect(()=>{
setPreGameData(preGameDataGroup.filter(obj => {return obj.id === PreGameKey})[0]);
},[PreGameKey]);
return(
<Search className="Search" preGameData={preGameDataGroup===null?noData:preGameDataGroup} setPreGameData={setPreGameDataGroup}></Search>
<PreGameMenu data={preGameDataGroup===null?noData:preGameDataGroup} function={setPreGameKey}></PreGameMenu>
);
}
export default PageComponent
The search below takes the data and the setdata functions. At the moment as the user enters into the search box the datagroup is filtered and set. This is the same datagroup as passed to the menu component and as a result the menu filters great. The problem is that this is permanent and if a user wants to perform multiple searches in a row the data has been filtered from the previous search. What is best practice here? Do I somehow call getData to reset the datagroup on a new search (no idea how to do this without over calling) or should I make a copy of the data when the original request is made? So I have a copy to filter and show in the menu but the filtering is always done on a unfiltered copy? Or, is there some other clever way to handle this issue without duplicating the data?
const Search =({preGameData, setPreGameData})=>{
const PreGameData = Array.from(preGameData)
const handleFilter = (e)=>{
const searchWord = e.target.value;
const newFilter = PreGameData.filter((item)=>{
return item.tradename.toLowerCase().includes(searchWord.toLowerCase())
})
setPreGameData(newFilter)
}
return (
<div className="Search">
<div className="SearchInputs">
<input type="text" placeholder="Search PreGame" onChange={handleFilter}></input>
</div>
<div className="SearchIcon">
<GoSearch></GoSearch>
</div>
</div>
);
}
export default Search

Why am I getting an empty array?

I am working on a product feedback app (with react) for my portfolio and came across an unexpected problem. The issue takes place in my SuggestionDetails component where I am getting the current id with useParams and filtering out the current product based on that id. Everything works and renders perfectly fine with the pre-existing suggestions array, but the problem starts when I try to render a new suggestion that I have created and added to the array.
This is how I am getting the current suggestion:
// I am getting the suggestions array through props
const { id } = useParams();
const [suggestion, setSuggestion] = useState(() => {
const currentSuggestion =
suggestions &&
suggestions.filter((suggestion) =>
suggestion.id === parseInt(id) ? suggestion : null
);
return currentSuggestion;
});
This is what the return value of the current suggestion should be (the new suggestion is still not created here):
Here when I try to filted out the new suggestion (the last element) I get an empty array:
I am still kind of new to this stuff and dont understand why this is happening. I have not added the code where I am creating a new suggestion and adding it to the current state, but I don't think the issue is there since it has clearly been created and added to current list of suggestion requests. Any information on this would be greatly appreciated, thank you.
The problem was that I was using parseInt instead of parseFloat to parse the id generated by Math.random()

How to add items to the watchlist in reactJs?

I Am trying to figure out how can I add the items to watchlist,
The steps am trying to carry out here are, when a user clicks on add button, the items should be added to the watchlist page/component which I have created.
Please see the hierarchy of the component.
I would like to show added items on the watchlist page.
Please see the code I tried.
const [watchlist, setWatchlist] = useState ([]);
const handleWatchlist = (movieData) => {
const newList = [...watchlist, movieData]
setWatchlist(newList)
console.log(newList)
}
<Button className = {classes.cardButton}size = "small" onClick = { ()=> handleWatchlist(movie) }> Add </Button>
When I try to inspect, the result is, it shows the items are added but can not pass on to the watchlist component? How can use a prop to pass this value and show them?
Any help is really appreciated.
Thanks a million
The Button doesn't pass any argument in handleWatchlist in your example. I don't know how Button component looks like, but passing the arg could look like the example below:
const Button = ({ onClick }) => {
const value = "some value";
return <button onClick={() => onClick(value)}>Button</button>;
};
const WatchList = () => {
...
return <Button onClick={handleWatchlist}>Add</Button>
Thanks for the support, but I figured out the solution by using two approaches and they are
Which is props drilling, i.e. is to perform the useState action in my App.js which is my main page where I have product and watchlist component.
This is the best way I would suggest other people use as well is by using the contextAPI and useContext hooks. A simple and easy way to pass any data anywhere in the app.
Please see the full code with the working solution below on the codesandbox.
https://codesandbox.io/s/determined-nightingale-m2mtn?file=/src/components/Products
The working app, where I can add the products to the watchlist.
working demo app

React components rendering with wrong props when changing filter

I have a page in a react app that uses a radio form to filter different objects of data that are being passed to the page.
The problem I am encountering, is that when I change the filter, (click on a different option on the radio form), only some of the data in the resulting list changes. A simple example of what happens is as follows:
Option one is selected with all the old data
Option two is selected, but only some of the new data comes through
First, I use an axios request to get an array of objects that will be used for the data:
componentDidMount() {
axios.get("xxxxxxxxx")
.then(result => {
this.setState({
data: result.data
});
});
Then, I create an array that filters the data from axios by an attribute based on which radio option is selected in the form:
let filteredData = [];
filteredData = this.state.data.filter(thisData => thisData.attribute === "attribute1");
Finally, I map all of the filtered data in the render function:
filteredData.map(filteredItem => ( <MyComponent key={i++} itemInfo={filteredItem.info} /> ))
In the definition of MyComponent, I use props to access the filtered item's info and put it into the table like this:
<td>{this.props.itemInfo.thisDataPoint}</td>
I'd love to hear if anybody has any idea why some of the components data updates when the filter changes, but not all of it. It seems weird to me that some data changes but some does not.
I have tried converting the props into state so that the component re-renders on the change but that did not work.
Thanks again for any help I get :)
given that filteredData is correct, and based on your code the issue must be on key={i++}. using some kind of implementation index can often lead to rendering problems, react will have trouble to distinguish the components since it uses the key to track them.
you should provide some unique identifier to each component as key like key={filteredItem.id}. if you don't have it, you can generate it with some library like uuid.

React - How to add "key" when pushing to an array

React v15.1
I am creating a table with a variable number of rows, depending on the data provided via props. Here is where I am (and it works fine):
getRows = () => {
const rows = [];
for (const col in this.props.tableRows) {
if ({}.hasOwnProperty.call(this.props.tableRows, col)) {
rows.push(React.cloneElement(this.props.tableRows[col], {}));
}
}
return rows;
}
I am working on making the console warnings disappear. This old favorite is appearing Each child in an array or iterator should have a unique "key" prop. Check the render method of 'TableData'.
What is the best way to add a key to cloned elements that I am pushing to an empty array?
OR is there a better way to handle this data on dynamically-generated table rows?
This is for an upload dialog for contact information I am using in many places. It successfully performs as expected, just need to add a key...or make it even better.
#medet-tleukabiluly has the right answer:
keyed_items = items.map((item, key) => React.cloneElement(item, {key}))
as long as each item is an element (not just a string).
It would probably make more sense to use the .map function and render JSX so you can easily assign a key to each table row.
function getRows() {
const {tableRows} = this.props;
return tableRows.map((row, index) =>
<tr key={index}>
// whatever else you wanted to add inside each row
</tr>
);
}
This is mostly just a guess for what you're trying to do - if it doesn't work for you, please post a comment that describes your problem in more detail and I can edit this answer to provide a better solution for you.

Categories

Resources