How to get individual items to display on a page? - javascript

database
I have an interesting bug in my code that I can`t figure out. It should be a simple React+Firestore setup, listing items on one page, and showing more details on each item on the next. Unfortunately, it only shows details for the first item on the list.
Have been digging through the Firestore documentation, where I found the following solution. It's not working...
Details
import React, { useState, useEffect } from "react";
import firebase from "./firebase";
import Servis from "./funkc/servisni";
export default function FireDetail({ match }) {
// console.log(match);
console.log(match.params.id);
const [item, setItem] = useState([]);
const [loading, setLoading] = useState(true);
const getIt = () => {
setLoading(true);
const item = [];
const docRef = firebase
.firestore()
.collection("polja")
.doc("id", "==", match.params.id);
docRef.onSnapshot((doc) => {
if (doc.exists) {
console.log("Document data:", doc.data());
setItem(doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
});
setLoading(false);
};
useEffect(() => {
getIt();
}, [match]);
if (loading) {
return <h3>samo malo...</h3>;
}
return (
<div className="container">
<div>
Kontakt: tip - email
<p> {item.Kontakt} </p>
</div>
<div>
<p>Datum rodjenja: {item.Datum}</p>
{item.Prezime} {item.Ime}
</div>
</div>
);
}
List
the component that lists all of the items in the database...
const SORTER = {
"Prezime A-Z": { column: "Prezime", direction: "asc" },
"Prezime Z-A": { column: "Prezime", direction: "desc" },
"Email A-Z": { column: "Kontakt", direction: "asc" },
};
const PAGER = {
5: { Max: "5" },
30: { Max: "30" },
45: { Max: "45" },
};
export default function FireList() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [sortBy, setSortBy] = useState("Prezime A-Z");
const [displayMax, setDisplayMax] = useState("5");
const [query, setQuery] = useState("");
// function routeTo() {
// const { id } = useParams();
// }
const ref = firebase
.firestore()
.collection("polja")
.orderBy(SORTER[sortBy].column, SORTER[sortBy].direction)
.limitToLast(PAGER[displayMax].column);
// console.log(ref);
function getEm() {
setLoading(true);
ref.get().then((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
const item = {
...doc.data(),
id: doc.id,
};
items.push(item);
});
setItems(items);
// console.log(items);
setLoading(false);
});
}
useEffect(() => {
getEm();
}, [query, sortBy, displayMax]);
return (
<div>
<div>
{" "}
<label>Poredaj</label>
<select
value={sortBy}
onChange={(e) => setSortBy(e.currentTarget.value)}
>
<option value="Prezime A-Z"> Prezime A-Z </option>
<option value="Prezime Z-A"> Prezime Z-A </option>
<option value="Email A-Z"> Email A-Z </option>
</select>
</div>
<div>
<label> Max. po stranici </label>
<select
value={displayMax}
onChange={(e) => setDisplayMax(e.currentTarget.value)}
>
<option value="5">5</option>
<option value="30">30</option>
<option value="45">45</option>
</select>
</div>
<ul>
<input
type="text"
value={query}
onChange={(event) => setQuery(event.target.value)}
></input>
</ul>
{loading ? <h1>Loading...</h1> : null}
{items.map((val) => (
<div key={val.id}>
<p>
{val.Ime} {val.Prezime}
<Link to={`/kontakt/detalji/${val.id}`}> ajd </Link>
</p>
</div>
))}
</div>
);
}
App component, providing navigation
return (
<BrowserRouter>
<div className="App">
login
<div>
<Header />
</div>
<Route path="/" exact component={Header} />
<Route path="/adresar" component={FireList} />
<Route path="/kontakt" exact component={ContactEdit} />
<Route path="/kontakt/detalji/:id" component={FireDetail} />
</div>
</BrowserRouter>
);
}
export default App;

I think you must read the url parameter on each render. Thath meanes useEffect( yourfunction, [match]) (avoid using [ ] as second parameter this time)
Remember, ReactRouter doesnt reload or load a page when route somwhere. All is in memory, except the first time.

Related

How do I make a search filter using a category array? NFT smart contract fullstack

bit of a newbie at js here and I'm creating a search filter for my NFT marketplace platform.
I've successfully been able to create a basic input function to search for the name of the item uploaded but because the category of the item is an array, I'm finding difficulty creating checkbox inputs to filter the search results by category.
Here's the piece my code with the search by name function:
export function Results() {
const { fetchNFTs, setError, currentAccount } = useContext(
NFTMarketplaceContext
);
const [nfts, setNfts] = useState([]);
const [nftsCopy, setNftsCopy] = useState([]);
useEffect(() => {
try {
// if (currentAccount) {
fetchNFTs().then((items) => {
setNfts(items.reverse());
setNftsCopy(items);
console.log(nfts);
});
// }
} catch (error) {
setError("Please reload the browser", error);
}
}, []);
const onHandleSearch = (value) => {
const filteredNFTS = nfts.filter(({ name }) =>
name.toLowerCase().includes(value.toLowerCase())
);
if (filteredNFTS.length === 0) {
setNfts(nftsCopy);
} else {
setNfts(filteredNFTS);
}
};
const onClearSearch = () => {
if (nfts.length && nftsCopy.length) {
setNfts(nftsCopy);
}
};
return {
<SearchBar
onHandleSearch={onHandleSearch}
onClearSearch={onClearSearch}
/>
}
And my search bar:
import React, { useEffect, useState } from "react";
const SearchBar = ({ onHandleSearch, onClearSearch }) => {
const [search, setSearch] = useState("");
const [searchItem, setSearchItem] = useState(search);
useEffect(() => {
const timer = setTimeout(() => setSearch(searchItem), 1000);
return () => clearTimeout(timer);
}, [searchItem]);
useEffect(() => {
if (search) {
onHandleSearch(search);
} else {
onClearSearch();
}
}, [search]);
return (
<div className="SearchBar">
<div className="section-filters-bar-actions">
<form className="form">
<div className="form-item split">
<div className="form-input small">
<label for="items-search">Search Items</label>
<input type="text" id="items-search" style={{width:'370px'}}
onChange={(e) => setSearchItem(e.target.value)}
value={searchItem}/>
</div>
</div>
</form>
</div>
</div>
);
}
export default SearchBar;
And finally the array in the upload page / function:
const UloadNFT = ({ uploadToIPFS, createNFT }) => {
const [price, setPrice] = useState("");
const [active, setActive] = useState(0);
const [name, setName] = useState("");
const [website, setWebsite] = useState("");
const [description, setDescription] = useState("");
const [royalties, setRoyalties] = useState("");
const [fileSize, setFileSize] = useState("");
const [category, setCategory] = useState(0);
const [properties, setProperties] = useState("");
const [image, setImage] = useState(null);
const router = useRouter();
const categoryArry = [
{
category: "AI Generated",
},
{
category: "Artwork",
},
{
category: "Audio",
},
{
category: "Collectible",
},
{
category: "Customization",
},
{
category: "Digital Land",
},
{
category: "Gaming",
},
{
category: "Utility",
},
];
return (
<div className="UloadNFT" style={{height:'1350px'}}>
<div style={{display:'inline-grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '0rem'}}>
<div className={Style.upload_box} style={{backgroundColor:'var(--primary-white)',padding:'30px 30px 30px 30px'}}>
<div className={formStyle.Form_box_input}>
<label htmlFor="nft">Item Name</label>
<input
type="text"
placeholder="Name your token..."
className={formStyle.Form_box_input_userName}
onChange={(e) => setName(e.target.value)}
style={{border:'1px solid #202020', backgroundColor:'transparent'}}
/>
</div>
// category upload input area
<div className={formStyle.Form_box_input}>
<label htmlFor="name">Choose Category</label>
<p className={Style.upload_box_input_para}>
Choose a specific category for your token
</p>
<br></br>
<div className={Style.upload_box_slider_div}>
{categoryArry.map((el, i) => (
<div
className={`${Style.upload_box_slider} ${
active == i + 1 ? Style.active : ""
}`}
key={i + 1}
onClick={() => (setActive(i + 1), setCategory(el.category))}
>
<p style={{textAlign:'center'}}>{el.category} </p>
</div>
))}
</div>
</div>
<Button
btnName="Create Token"
handleClick={async () =>
createNFT(
name,
price,
image,
description,
router,
category,
// royalties,
// fileSize,
website
// properties
)
}
/>
</div>
</div>
I know it's a lot here since I'm passing the value through multiple functions but I've tried to narrow it down as much as possible. Also the smart contract is working perfectly fine and holds the category variable. I'm sure I just need to call it properly now but it's an array.
Please help!
I tried to replace { name } and name.toLowerCase() with category just to test it but it said 'category.toLowerCase() is undefined'.
Then I tried category.toString().toLowerCase() but it gave the same result.

Create a multi level dropdown list in react from JSON list of objetcs

Hello im new to react and Im hoping someone can help out. So I have a JSON file from an api i made and this is the request to get all theaters, I only have one theater for this api but that theater has multiple movies, showtimes
{
"theatreId": 1,
"theatreName": "Scotiabank Theater Chinook",
"movies": [
{
"movieId": 4,
"movieName": "Now You See Me",
"dateAdded": "2022-12-31",
"showtimes": [
{
"showtimeId": 14,
"showtimeDate": "2022-12-10",
"showtimeTime": "11:00:00",
"seats": [
{
"seatId": 218,
"seatNum": 10,
"theTicket": null
},
{
"seatId": 220,
"seatNum": 12,
"theTicket": null
},
{
"seatId": 214,
"seatNum": 6,
"theTicket": null
},
{
"seatId": 210,
"seatNum": 2,
"theTicket": null
},
{
"seatId": 219,
"seatNum": 11,
"theTicket": null
},
....{more data points here}
I am trying to create a multi level select option dropdown list i.e. when I select a menu from the first dropdown, based on that option the next dropdown would be a list of options of what was in the previous option was.
In this case, I have just one cinema, "Scotibank Chinook" when I select that cinema option, I want the next option which is movie to be a list of movies based on "movies" since its values is an array of objects and the same for showtimes and seats as seen in the JSON file.
I have a react code where I make each name that has an array of objects to make useState list of those object names, my main issue is to navigate into the array of objects and setState of the List to be the List of objects
import React, {useState,useEffect} from 'react';
import axios from 'axios';
function Form() {
const [theaterName, setTheaterName] = useState("")
const [movieName, setMovieName] = useState("")
const [showTime, setShowTime] = useState("")
const [theaterList, setTheaterList] = useState([{'theatreId':''}])
const [movieList, setMovieList] = useState([{'movieId':''}])
const [showTimeList, setShowTimeList] = useState([{'showtimeId':''}])
useEffect(() =>{
fetchTheater();
fetchMovie();
fetchShowTime()
}, [])
const fetchTheater = () => {
axios.get('http://localhost:8080/api/v1/theatre')
.then(response => {
console.log(response.data)
setTheaterList(response.data);
})
.catch(error => console.log(error));
}
const fetchMovie = () => {
axios.get('http://localhost:8080/api/v1/movie')
.then(response => {
console.log(response.data)
setMovieList(response.data);
})
.catch(error => console.log(error));
}
const fetchShowTime = () => {
axios.get('http://localhost:8080/api/v1/showtime')
.then(response => {
console.log(response.data)
setShowTimeList(response.data);
})
.catch(error => console.log(error));
}
const handleTheaterChange = (event) =>{
setTheaterName(event.target.value);
}
const handleMovieChange = (event) =>{
setMovieName(event.target.value);
}
const handleShowTimeChange = (event) =>{
setShowTime(event.target.value);
}
const saveBtn = (e) => {
e.preventDefault();
console.log('Theater Selected',theaterName);
console.log('Movie Selected',movieName);
console.log('Showtime Selected',showTime);
}
return (
<div>
<div className="container-fluid">
<div className="row">
<div className="col-sm-4">
<h2 className="alert alert-warning">Movies</h2>
<br />
<select className="form-control" value={theaterName} onChange={handleTheaterChange}>
<option value="">Choose theatre</option>
{theaterList.map(theater => (
<option key={theater.theatreId} >
{theater.theatreName}
</option>
))}
</select>
<br/>
<select className="form-control" value={movieName} onChange={handleMovieChange}>
<option value="">Choose Movie</option>
{movieList.map(movie => (
<option value={movie.movieName} key={movie.movieId} >{"Hello"}</option>
))}
</select>
<br/>
<select className="form-control" value={showTime} onChange={handleShowTimeChange}>
<option value="">Choose showtime</option>
{showTimeList.map(showtime => (
<option value={showtime.showtimeDate} key={showtime.showtimeId} >{showtime.showtimeDate}</option>
))}
</select>
<button className="btn btn-primary" onClick={saveBtn}>Save</button>
</div>
</div>
</div>
</div>
)
}
export default Form
currently I am accessing each option by fetching the individual api endpoints for the the options and setting the state to a setState List
You only need one api which is the theater endpoint.
I don't know which backend you are using, but you need one response, it should contain all these nested lists.
then simply in react, use this logic
import React, {useState,useEffect} from 'react';
import axios from 'axios';
function Form() {
const [theater, setTheater] = useState("")
const [movie, setMovie] = useState("")
const [showTime, setShowTime] = useState("")
const [theaterList, setTheaterList] = useState([])
const [movieList, setMovieList] = useState([])
const [showTimeList, setShowTimeList] = useState([])
useEffect(() =>{
fetchTheater();
}, [])
const fetchTheater = () => {
/*using fetch
fetch(`http://localhost:8080/api/v1/theatre`,
{
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(res => res.json()).then(
data => {
console.log(data);
setTheaterList(data);
//setReady(true);
console.log("theater id: "+data[0].theaterId);
}).catch(error => {
console.log(error);
});*/
// using axios
axios.get('http://localhost:8080/api/v1/theatre')
.then(response => {
console.log(response.data)
setTheaterList(response.data);
})
.catch(error => console.log(error));
}
const handleTheaterChange = (event) =>{
let id = event.target.value;
console.log("theater changed: "+id);
//setTheater(event.target.value);
theaterList.map(theater => {
console.log(theater.theaterId);
if(theater.theaterId === parseInt(id)){
console.log("theater found "+theater.theaterId);
setMovieList(theater.movies);
setTheater(theater);
}
});
}
const handleMovieChange = (event) =>{
let id = event.target.value;
console.log("movie changed: "+id);
movieList.map(movie => {
console.log(movie.movieId);
if(movie.movieId === parseInt(id)){
console.log("theater found "+movie.movieId);
setShowTimeList(movie.showtimes)
setMovie(movie);
}
});
}
const handleShowTimeChange = (event) =>{
let id = event.target.value;
console.log("showtime changed: "+id);
showTimeList.map(showtime => {
console.log(showtime.showtimeId);
if(showtime.showtimeId === parseInt(id)){
console.log("showtime found "+showtime.showtimeId);
// furthermore, you can set the seat list
//setSeatList(showtime.seats)
setShowTime(showtime);
}
});
}
const saveBtn = (e) => {
e.preventDefault();
console.log('Theater Selected',theater.theaterName);
console.log('Movie Selected',movie.movieName);
console.log('Showtime Selected',showTime.showtimeTime);
}
return (
<div>
<div className="container-fluid">
<div className="row">
<div className="col-sm-4">
<h2 className="alert alert-warning">Movies</h2>
<br />
<select className="form-control" onChange={handleTheaterChange}>
<option value="">Choose theatre</option>
{theaterList.map(theater => (
<option value={theater.theaterId} key={theater.theaterId}>
{theater.theaterName}
</option>
))}
</select>
<br/>
<select className="form-control" onChange={handleMovieChange}>
<option value="">Choose Movie</option>
{movieList.map(movie => (
<option value={movie.movieId} key={movie.movieId} >{movie.movieName}</option>
))}
</select>
<br/>
<select className="form-control" onChange={handleShowTimeChange}>
<option value="">Choose showtime</option>
{showTimeList.map(showtime => (
<option value={showtime.showtimeId} key={showtime.showtimeId} >{showtime.showtimeDate}</option>
))}
</select>
<button className="btn btn-primary" onClick={saveBtn}>Save</button>
</div>
</div>
</div>
</div>
)
}
export default Form
important! change the word 'theatre' to 'theater', or you use either of them, but consistently.

Problem rendering data from Local Storage in React App

I have problem with rendering data from local storage on every refresh or reload. It renders only hard coded data but not data that I save in LS. It shows data in LS but not rendering. If anyone could explain or tell me what is wrong or give me directions to do something better would be grateful.I am farely new in Reactand would apretiate for insights. I ve put some dummy data. I ve sent componnets which could affect.
import { useState, useEffect } from "react";
//COMPONENTS:
import ScrollToTop from "./components/ScrollToTop";
import Footer from "./components/Footer";
import Home from "./components/Home";
import NavBar from "./components/NavBar";
import PhoneBook from "./components/PhoneBook";
function App() {
const date = new Date().toLocaleDateString();
const [contacts, setContacts] = useState([
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Vekjko Petrovic",
address: "121 Town Commons Way Phoenix, AZ, 45215",
phone: 123_465_689,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Marko Petrovic",
address: "Srbina 35, 11300 Smederevo Srbija",
phone: 256_269_866,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Michael Jackson",
address: "52 City St, Detroit, Mi, 46218",
phone: 359_525_555,
date,
},
{
id: Math.random().toString(36).substr(2, 9),
fullName: "Vanessa Parady",
address: "11 Beogradska Beograd, SRB, 11000",
phone: 123_465_689,
date,
},
]);
useEffect(() => {
const savedContacts = JSON.parse(localStorage.getItem("contacts"));
if (savedContacts) {
setContacts(savedContacts);
}
}, []);
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
const [searchContact, setSearchContact] = useState("");
const [theme, setTheme] = useState("dark");
const changeTheme = () => {
theme === "dark" ? setTheme("light") : setTheme("dark");
};
const addContact = (fullName, phone, address, email) => {
const newContacts = {
id: Math.random().toString(36).substr(2, 9),
fullName,
address,
phone,
email,
date,
};
const newContact = [...contacts, newContacts];
setContacts(newContact);
};
const deleteContact = (id) => {
const remainedContacts = contacts.filter((item) => item.id !== id);
setContacts(remainedContacts);
};
return (
<div data-theme={theme} className="app-container">
<ScrollToTop />
<NavBar changeTheme={changeTheme} currentTheme={theme} />
<Home />
<PhoneBook
contacts={contacts.filter((contact) =>
contact.fullName.toLowerCase().includes(searchContact)
)}
handleAddContact={addContact}
deleteContact={deleteContact}
handleSearchContacts={setSearchContact}
/>
<Footer />
</div>
);
}
export default App;
import React from "react";
import "../index.css";
//ASSETS:
import NewContact from "./NewContact";
import Contact from "./Contact";
import Search from "./Search";
function PhoneBook({
contacts,
handleAddContact,
deleteContact,
handleSearchContacts,
}) {
return (
<div id="phone_book" className="contacts-list">
<Search handleSearchContacts={handleSearchContacts} />
{contacts.map((contact) => {
return (
<Contact
key={contact.id}
id={contact.id}
fullName={contact.fullName}
address={contact.address}
phone={contact.phone}
email={contact.email}
date={contact.date}
deleteContact={deleteContact}
/>
);
})}
<NewContact handleAddContact={handleAddContact} />
</div>
);
}
export default PhoneBook;
import React from "react";
import profile from "../assets/images/profile.png";
import { MdDeleteForever } from "react-icons/md";
function Contact({ fullName, address, phone, email, id, date, deleteContact }) {
return (
<div className="contact">
<p className="contact-header">
<span>
<i>{fullName} </i>
</span>
<img src={profile} alt="profile" />
</p>
<div className="contact-footer">
<p>
{" "}
<i>Address: </i>
{address}
</p>
<p>
<i>Phone:</i> {phone}
</p>
<p>
{" "}
<i>Email:</i> {email}
</p>
<MdDeleteForever
onClick={() => deleteContact(id)}
className="delete-icon"
size="1.3rem"
/>
<p className="span-date">
<i>Date: </i>
{date}
</p>
</div>
</div>
);
}
export default Contact;
import React, { useState } from "react";
function NewContact({ handleAddContact }) {
const [fullName, setFullName] = useState("");
const [phone, setPhone] = useState("");
const [address, setAddress] = useState("");
const [email, setEmail] = useState("");
const handleSaveClick = () => {
if (!(fullName.trim().length > 0)) {
return;
}
handleAddContact(fullName, phone, address, email);
setFullName("");
setPhone("");
setAddress("");
setEmail("");
};
return (
<div className="contact new last">
{" "}
<p className="inputs">
<span>Create New Contact</span>
<label>Full Name:</label>
<input
type="text"
placeholder="Enter..."
value={fullName}
onChange={(e) => setFullName(e.target.value)}
/>
<label> Address:</label>
<input
type="text"
placeholder="Enter..."
value={address}
onChange={(e) => setAddress(e.target.value)}
/>
<label> Phone:</label>
<input
type="text"
placeholder="Enter..."
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
<label>Email:</label>
<input
type="text"
placeholder="Enter..."
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</p>
{/* <img src={profile} alt="fullname" /> */}
<div className="save-list-footer">
<button className="save" onClick={handleSaveClick}>
SAVE
</button>
</div>
</div>
);
}
export default NewContact;
import styled from "styled-components";
import React from "react";
import { MdSearch } from "react-icons/md";
//STYLES
import "../index.css";
function Search({ handleSearchContacts }) {
return (
<SearchComponent className="search">
<MdSearch className="search-icon" size="1.3em" />
<input
type="text"
placeholder="Search..."
onChange={(e) => handleSearchContacts(e.target.value)}
/>
</SearchComponent>
);
}
export default Search;
Took me some messing around but I think I have an example that might be doing what you are describing. It seems like the following code may be the culprit:
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
Not in your example I assume you are initializing contacts like such:
const [contact, setContacts] = useState([])
When this state is initialized it will trigger that useEffect and set the localStorage.setItem("contacts" , []) which will make it look like nothing is being rendered. I think the easiest fix would be to move the localStorage.setItem into the addContacts function.
Here is a simplified version of how to set it up:
export const Contacts = () => {
const [contacts, setContacts] = useState([]);
useEffect(() => {
const savedContacts = localStorage.getItem("contacts");
if (savedContacts) {
setContacts(JSON.parse(savedContacts));
}
}, []);
// useEffect(() => {
// //This is your issue here Comment out this block and comment in the setItem in the addContact
// localStorage.setItem("contacts", JSON.stringify(contacts));
// }, [contacts]);
const addContact = (newContact) => {
const newContactList = [...contacts, newContact];
setContacts(newContactList);
localStorage.setItem("contacts", JSON.stringify(newContactList));
};
return (
<div>
<InputContact addContact={addContact} />
{contacts.map((data, i) => (
<Contact data={data} key={i} />
))}
</div>
);
};
You can find a working example of this on code sandbox. There is some explanation of the app in the App.js and Contacts.jsx. https://codesandbox.io/s/localstorage-contacts-s9dfzc?file=/src/Contacts.jsx:130-969

Delayed post parameters when submitting via onChange in reactjs

I'm trying to send a parameter to the api to give me an exact json response, but when i'm trying to submit my form via select onChange={onAddSubmit}, it is still passing the default value 146846 but I already changed my select to 146847 so i'm getting the invalid response.
Home.js
import React, { useEffect, useState } from "react";
import Api from "../Api";
import AppContainer from "../tmp/AppContainer";
import HomeContainer from "./HomeContainer";
const Home = () => {
const [posts, setPosts] = useState();
const [loading, setLoading] = useState(false);
const [allValues, setAllValues] = useState({
contractId: "146846",
planId: "1028",
dateStart: "2021-01-30",
dateEnd: "2021-01-31",
numberOfAdults: 1,
numberOfChildren: 0,
planOption: "Individual",
unit: "day",
});
const changeHandler = (e) => {
setAllValues({ ...allValues, [e.target.name]: e.target.value });
};
const onAddSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
await Api.getCurlPost({
...allValues,
}).then((response) => {
const result = response.data;
setPosts(result.data);
});
} catch {
alert("Failed to add post!");
} finally {
setLoading(false);
}
};
useEffect(() => {
onAddSubmit;
}, []);
return (
<AppContainer>
<HomeContainer
onAddSubmit={onAddSubmit}
changeHandler={changeHandler}
loading={loading}
posts={posts}
/>
</AppContainer>
);
};
export default Home;
Here is my HomeContainer.js that contains my html and bootstrap design
import React, { Component } from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faPlane } from "#fortawesome/free-solid-svg-icons";
import { faCircleNotch } from "#fortawesome/free-solid-svg-icons";
class HomeContainer extends Component {
render() {
const { onAddSubmit, changeHandler, loading, posts } = this.props;
return (
<div>
<div className="row mb-auto">
<div className="col-md-6 p-2">
<img
width="100%"
src="../resources/img/starr/7437.jpg"
/>
<div className="mt-3 shadow-sm p-3 mb-5 bg-white rounded">
<h3 className="text-center">
<FontAwesomeIcon
icon={faPlane}
rotation={0}
style={{ marginRight: 5 }}
/>
Travel Details
</h3>
<form onChange={onAddSubmit}>
<div className="form-group">
<select
className="form-control"
name="contractId"
onChange={changeHandler}
>
<option value="146846">
TravelLead Domestic Travel Insurance
</option>
<option value="146847">
TravelLead International Travel
Insurance
</option>
</select>
</div>
<div className="form-group">
<select
className="form-control"
name="planId"
onChange={changeHandler}
>
<option value="1028">
Economy (Single Trip)
</option>
<option value="1029">
Elite (Single Trip)
</option>
</select>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
}
export default HomeContainer;
I figured it already, I just added allValues as a parameter when calling onAddSubmit on my useEffect hook, and if there is something changes happen to allValues list it will automatically submit a request to the API and throw a response.
useEffect(() => {
onAddSubmit(allValues);
}, [allValues]);
And onAddSubmit function, just change the ...allValues to ...data on api parameter that sends a request to axios.
const onAddSubmit = async (data) => {
setLoading(true);
try {
await Api.getCurlPost({
...data,
}).then((response) => {
const result = response.data;
setPosts(result.data);
});
} catch {
alert("Failed to add post!");
} finally {
setLoading(false);
}
};

Search does not work like expect in react

In my application i use a search input to search values, and select input also to filter values from my data. Now my component looks like below:
export default function App() {
const [myData, setMydata] = useState([]);
const searchData = e => {
const v = e.target.value;
const res= data.filter(i =>
i.name.toLowerCase().includes(v.toLowerCase())
);
setMydata(res);
};
function handleChange(value) {
const res= data.filter(i => i.age === Number(value));
setMydata(res);
}
return (
<div className="App">
<Select defaultValue="" style={{ width: 120 }} onChange={handleChange}>
<Option value="2">2</Option>
<Option value="32">32</Option>
</Select>
<input onChange={searchData} />
<h1>Data</h1>
{myData.map((i, k) => (
<div key={k}>
{i.name} is <span>{i.age}</span>
</div>
))}
</div>
);
}
Now, the functionality works. If you search something, appear results, and if you try to select a value, also appears the value that you selected.
Issue: If i select from dropdown, for example: 32, appears:
Julia is 32
Bill is 32
Bill is 32
And now if i want to search from the list above just Julia, i type Julia in search, it search from the whole list of data, not just from the list which i get after i selected 32. How to solve this, and how to get the result from the last results, not to search from the whole list, but from the last result?
Note: the same issue is when i search first and after that i select a value from dropdown.
Your two filters always work with the same object data, and not previously filtered state data myData. Best practice save value of filters in state and each render filter data:
export default function App() {
const [age, setAge] = useState('');
const [name, setName] = useState('');
const filteredData = data
.filter(i => Boolean(age) ? i.age === Number(age) : true)
.filter(i => i.name.toLowerCase().includes(name.toLowerCase()));
return (
<div className="App">
<Select value={age} style={{ width: 120 }} onChange={setAge}>
<Option value="2">2</Option>
<Option value="32">32</Option>
</Select>
<input value={name} onChange={e => setName(e.target.value)} />
<h1>Data</h1>
{filteredData.map((i, k) => (
<div key={k}>
{i.name} is <span>{i.age}</span>
</div>
))}
</div>
);
}
Try this one out:
import React, { useState } from "react";
export default function App() {
const data = [
{ age: 2, name: 'John' },
{ age: 32,name: 'Mark' },
{ age: 22,name: 'Dell' },
{ age: 14,name: 'Linda' },
{ age: 16,name: 'Jon' },
{ age: 18,name: 'Ron' }
];
const [myData, setMydata] = useState([]);
const searchData = e => {
const v = e.target.value;
const res = data.filter(i =>
i.name.toLowerCase().includes(v.toLowerCase())
);
setMydata(res);
};
function handleChange(value) {
const res = data.filter(i => i.age === Number(value.target.value));
console.log("This is the value and respos", value.target.value);
setMydata(res);
}
return (
<div>
<select defaultValue="" style={{ width: 120 }} onChange={handleChange}>
<option value="2">2</option>
<option value="32">32</option>
</select>
<input onChange={searchData} />
<h1>Data</h1>
{myData.map((i, k) => (
<div key={k}>
{i.name} is <span>{i.age}</span>
</div>
))}
</div>
);
}
Here is the codesandbox demo: Demo

Categories

Resources