How do you create multiple search in React and javascript? - javascript

I don't know how to make multiple searches while I'm doing my assignment.
I'm trying a lot of things. If anyone knows, please answer.
app.jsx
const [touristSpot, setTouristSpot] = useState([]);
const [filterTourlistSpot, setFilterTourlistSpot] = useState([]);
const [searchItem, setSearchItem] = useState("");
const filedConfig = {
method: "get",
url: "http://localhost:3000/fields",
};
const recordConfig = {
method: "get",
url: "http://localhost:3000/records",
};
useEffect(
() =>
axios(filedConfig)
.then((res) => console.log(res?.data))
.catch((err) => console.log(err)),
[]
);
useEffect(
() =>
axios(recordConfig)
.then((res) => setTouristSpot(res?.data))
.catch((err) => console.log(err)),
[]
);
console.log(searchItem);
useEffect(() => {
setFilterTourlistSpot(() =>
// touristSpot?.filter((spot) => spot.관광지명.includes(searchItem)) //first try
// touristSpot?.filter((spot) => new RegExp(searchItem).test(spot.관광지명))//second try
touristSpot?.filter((spot) => spot.관광지명.match(searchItem))//final try
);
}, [searchItem, touristSpot]);
return (
<>
<Header />
<Search
touristSpot={touristSpot}
setTouristSpot={setTouristSpot}
filterTouristSpot={filterTourlistSpot}
setFilterTouristSpot={setFilterTourlistSpot}
searchItem={searchItem}
setSearchItem={setSearchItem}
/>
<SpotList filterTourlistSpot={filterTourlistSpot} />
</>
);
spotlist.jsx
const Spotlist = ({ filterTourlistSpot }) => {
return (
<div className={styles.container}>
{filterTourlistSpot.map((spot) => (
<SearchSpot spot={spot} />
))}
</div>
);
};
searchspot.jsx
const Searchspot = ({ spot }) => {
const onClick = (e) => {
console.log(spot);
};
return (
<div className={styles.spotbox} onClick={onClick}>
<h3>{spot.관광지명}</h3>
</div>
);
};
What I want is to show you the search results that fit the keyword when you enter more than one keyword.
Together in the situation below.

Your details are a bit unclear, you should provide the errors you are getting, if any, and if possible a translation of the words that are not in english, since they seem to be used as variables and/or props.
If your error happens during the mapping in spotlist.jsx and everything else is working, then try this:
spotlist.jsx
const Spotlist = ({ filterTourlistSpot }) => {
return (
<div className={styles.container}>
{filterTourlistSpot().map((spot) => (
<SearchSpot spot={spot} />
))}
</div>
);
};
You forgot to call your filterTourlistSpot function before mapping the array returned from the filtering inside the body of that function.
If this does not solve your issue, please provide some more information about your problem and I will edit my answer to give a better solution.

Related

API fetch in React

the screenshots attached are the result of an API fetch (movie database).
From this results, as shown in the screenshots i am trying to reach for the "primaryImage.url" yet I keep on getting "Cannot read properties of undefined (reading 'url').
Here is my page:
const SearchPage = () => {
const params = useParams();
const { query } = params;
const [data, setData] = useState(null);
const fetchData = () => {
fetch(`${rapidApiUrl}/search/title/${query}${rapidSearchData}`, rapidApiOptions)
.then((response) => response.json())
.then((data) => {
setData(data.results);
})
.catch((err) => console.error(err));
};
useEffect(() => {
fetchData();
}, [query]);
console.log(data)
return (
<div>
{data &&
data.map((media) => (
<div key={media.id}>
{/* <img src={media.primaryImage.url} alt={media.titleText.text} /> */}
<p>{media.titleText.text}</p>
<p>{media.releaseYear.year}</p>
</div>
))}
</div>
);
};
export default SearchPage;
As you are looping through the data, some of the primaryImage values are objects, which do indeed have a url property, but some of them are null. When attempting to find the url property of null, it errors out. You probably want to check to see if primaryImage is null and handle it differently than if it has a value.
The problem is primaryImage property appears to be null for few cases. You should use optional chaining to avoid the errors.
return (
<div>
{data &&
data.map((media) => (
<div key={media.id}>
<img src={media.primaryImage?.url} alt={media.titleText?.text} /> */}
<p>{media.titleText.text}</p>
<p>{media.releaseYear.year}</p>
</div>
))}
</div>
);
You can read more about optional chaining here

Rendering nested object properties from API call in react

I am trying to render text from an API call, text or numbers that are directly accesible from the axios.data object can render normally, nevertheless when inside the axios.data there is another object with its own properties I cannot render because an error shows, the error is 'undefined is not an object (evaluating 'coin.description.en')', over there description is an object; my code is
function SINGLE_COIN(props) {
const { id } = useParams()
console.log(id);
const SINGLE_API = `https://api.coingecko.com/api/v3/coins/${id}?tickers=true&market_data=true&community_data=true&developer_data=true&sparkline=true`
const [coin, setCoin] = useState({})
useEffect(() => {
axios
.get(SINGLE_API)
.then(res => {
setCoin(res.data)
console.log(res.data)
})
.catch(error => {
console.log(error)
})
}, [])
return (
<div>
<h2>{coin.name}</h2>
<div>{coin.coingecko_score}</div>
<div>{coin.liquidity_score}</div>
<div>{coin.description.en}</div>
<SINGLE_COIN_DATA coin={coin} />
</div>
)
}
Thanks!
For the initial render (data is not fetched yet), it will be empty. so nested property would be undefined.
so note the changes:
Example 1:
const [coin, setCoin] = useState(null);
..
return (
<div>
{coin ? (
<>
<h2>{coin.name}</h2>
<div>{coin.coingecko_score}</div>
<div>{coin.liquidity_score}</div>
<div>{coin.description.en}</div>
</>
) : null}
</div>
);
Example:2: Use the optional chaining while accessing nested property
return (
<div>
<h2>{coin?.name}</h2>
<div>{coin?.coingecko_score}</div>
<div>{coin?.liquidity_score}</div>
<div>{coin?.description?.en}</div>
</div>
);
And the complete code with : working example
export default function SINGLE_COIN() {
const { id } = useParams()
const SINGLE_API = `https://api.coingecko.com/api/v3/coins/${id}?tickers=true&market_data=true&community_data=true&developer_data=true&sparkline=true`;
const [coin, setCoin] = useState(null);
useEffect(() => {
axios
.get(SINGLE_API)
.then((res) => {
setCoin(res.data);
})
.catch((error) => {
console.log(error);
});
}, []);
return (
<div>
{coin ? (
<>
<h2>{coin.name}</h2>
<div>{coin.coingecko_score}</div>
<div>{coin.liquidity_score}</div>
<div>{coin.description.en}</div>
</>
) : null}
</div>
);
}

Why will my fetch API call map one nested objects, but not the other?

I'm parsing data from the NASA API using React, and for some reason I can map one nested object within the return but not the other.
Here is my parent component:
import React, { useState } from 'react'
import './NasaAPI.scss'
import NasaImages from './NasaImages'
const NasaAPI = () => {
const [nasaData, setNasaData] = useState([])
const [nasaImage, setNasaImage] = useState("")
const [searchInput, setSearchInput] = useState("")
const [loading, setLoading] = useState(true)
const fetchData = async (e) => {
const data = await fetch(`https://images-api.nasa.gov/search?q=${searchInput}`)
.then(response => response.json())
.then(data => setNasaData(data.collection.items))
.catch(err => console.log(err))
.finally(setLoading(false))
}
const handleSubmit = (e) => {
e.preventDefault()
fetchData()
}
const handleChange = (e) => {
setSearchInput(e.target.value)
}
return (
<div>
<h2>Search NASA Images</h2>
<form onSubmit={handleSubmit}>
<input name="searchValue" type="text" value={searchInput} onChange={handleChange}></input>
<button value="Submit">Submit</button>
</form>
<section>
<NasaImages nasaData={nasaData} loading={loading}/>
</section>
</div>
)
}
export default NasaAPI
Here's where the issue is, in the child component:
import React from 'react'
const NasaImages = ({ nasaData }) => {
console.log(nasaData)
return (
<div>
<h2>This is a where the data go. 👇</h2>
{
nasaData && nasaData.map((data, idx) => {
return (
<div key={idx}>
<p>{data.href}</p>
<div>
{/* {data.links.map((data) => {
return <p>{data.href}</p>
})} */}
{data.data.map((data) => {
return <p>{data.description}</p>
})}
</div>
</div>
)
})
}
</div>
)
}
export default NasaImages
The current configuration works, and will display a data.description (data.data.map) mapping property. However, I want the commented code immediately above it to work which displays a data.href (data.links.map) property.
The JSON looks as follows:
So, the issue is that I can map one set of properties, data.data.map, but cannot access the other in the same object, data.links.map, without getting the error "TypeError: Cannot read property 'map' of undefined". Thank you in advance!
There exists a data element sans a links property, in other words there is some undefined data.links property and you can't map that. Use Optional Chaining operator on data.links when mapping, i.e. data.links?.map. Use this on any potentially undefined nested properties.
const NasaImages = ({ nasaData = [] }) => {
return (
<div>
<h2>This is a where the data go. 👇</h2>
{nasaData.map((data, idx) => (
<div key={idx}>
<p>{data.href}</p>
<div>
{data.links?.map((data, i) => <p key={i}>{data.href}</p>)}
{data.data?.map((data, i) => <p key={i}>{data.description}</p>)}
</div>
</div>
))}
</div>
)
}

React - Sharing state and methods between sibiling components

This is somewhat of a design or react patterns related question but I'm trying to figure out the best way to share sate and methods across different children.
I have a small app where the navigation from step to step and actual form data are rendered and handled in different sibling components. This is a codesandbox of roughly how the app functions.
What I was trying to figure out is the best way to share state between the sibling components. For instance, in the app linked above I need to validate the input from <AppStepOne /> when next is clicked and then move to <AppStepTwo />. Ideally I don't want to just have all the state live in the top level ExampleApp because there are a decent amount of steps and that can get ugly really fast.
The other though I had which I wanted to get some input on what using the react context api. I haven't worked with it before so I wanted to get some idea as if it's something that could possible work as clean solution for this.
Code for app above:
const ExampleApp = () => {
const [currentStep, setCurrentStep] = useState(1);
const getCurrentAppStep = () => {
switch (currentStep) {
case 1:
return {
app: <AppStepOne />,
navigation: (
<AppNavigation onNext={() => setCurrentStep(currentStep + 1)} />
)
};
case 2:
return {
app: <AppStepTwo />,
navigation: (
<AppNavigation onNext={() => setCurrentStep(currentStep + 1)} />
)
};
default:
return {
app: <AppStepOne />,
navigation: (
<AppNavigation onNext={() => setCurrentStep(currentStep + 1)} />
)
};
}
};
const myAppStep = getCurrentAppStep();
return (
<div>
<ParentComp>
<ChildOne>{myAppStep.app}</ChildOne>
<ChildTwo>{myAppStep.navigation}</ChildTwo>
</ParentComp>
</div>
);
};
const ParentComp = ({ children }) => {
return <div>{children}</div>;
};
const ChildOne = ({ children }) => {
return <div>{children}</div>;
};
const ChildTwo = ({ children }) => {
return <div>{children}</div>;
};
const AppStepOne = () => {
const [name, setName] = useState("");
return (
<div>
Name: <input onChange={(e) => setName(e.target.value)} />
</div>
);
};
const AppStepTwo = () => {
const [zipcode, setZipCode] = useState("");
return (
<div>
Zipcode: <input onChange={(e) => setZipCode(e.target.value)} />
</div>
);
};
const AppNavigation = ({ onNext }) => {
return <button onClick={onNext}>Next</button>;
};

How can I set a loading state on a specific element of an array?

I have a list of components coming out of an array of objects. See the code:
const SitesList = () => {
const [loadingState, setLoadingState] = useState(false);
const copySite = (site) => {
setLoadingState(true);
copySiteAction(site)
.then(() => setLoadingState(false))
.catch(() => setLoadingState(false));
};
return filterSites.map((s, i) => (
<div>
{!loadingState ? (
<>
<p>Site: {s.name}</p>
<button onClick={() => copySite(s)}>Copy Site</button>
</>
) : (
<LoadingStateComponent />
)}
</div>
));
};
I want to show the component <LoadingStateComponent /> only on the index/component when I click the Copy Site button. As it is right now, every time I click on that button, all of the components disappear, hence what I see is the <LoadingStateComponent /> until loadingState is set to false.
Any ideas on how can I achieve this?
Rather than having a single "loading" state value, you need one for each item in the array. So, you basically need a second array that's the same size as filterSites to track the state of each index. Or, perhaps a better way would be a simple map linking indices to their corresponding loading state, so that you don't even need to worry about creating an array of X size.
const SitesList = () => {
const [loadingState, setLoadingState] = useState({});
const copySite = (site, index) => {
setLoadingState({...loadingState, [index]: true});
copySiteAction(site)
.then(() => setLoadingState(oldLoadingState => ({...oldLoadingState, [index]: false})))
.catch(() => setLoadingState(oldLoadingState => ({...oldLoadingState, [index]: false})));
};
return filterSites.map((s, i) => (
<div>
{!loadingState[i] ? (
<>
<p>Site: {s.name}</p>
<button onClick={() => copySite(s, i)}>Copy Site</button>
</>
) : (
<LoadingStateComponent />
)}
</div>
));
};
This may or may not solve your problem, but it will solve other problems and its too long for a comment.
This:
const SitesList = () => {
const [loadingState, setLoadingState] = useState(false);
const copySite = (site) => {
setLoadingState(true);
copySiteAction(site)
.then(() => setLoadingState(false))
.catch(() => setLoadingState(false));
};
return filterSites.map((s, i) => (
<div>
{!loadingState ? (
<>
<p>Site: {s.name}</p>
<button onClick={() => copySite(s)}>Copy Site</button>
</>
) : (
<LoadingStateComponent />
)}
</div>
));
};
Needs to look more like this:
const SitesList = () => {
const [loadingState, setLoadingState] = useState(false);
useEffect(() => {
if (loadingState) {
apiCall()
.then(whatever)
.catch(whatever)
.finally(() => setLoadingState(false));
}
}, [loadingState]);
return filterSites.map((s, i) => (
<div key={s.id}> // Note the key
{!loadingState ? (
<>
<p>Site: {s.name}</p>
<button onClick={() => setLoadingState(true)}>Copy Site</button>
</>
) : (
<LoadingStateComponent />
)}
</div>
));
};
React assumes that your pure functional component is a pure function. If you violate that assumption it is under no obligation to respect your side-effects or render them when you'd expect. You need to wrap any side-effects (like a xhr request) in a useEffect hook, and like all hooks it must be called unconditionally. The way I've written it the hook will be called every time loadingState changes and will make the call if it is true, you may need to tweak for your actual use case.
Additionally, items rendered from an array need a unique key prop, I'm assuming your sites have ids but you will need to figure out a way to generate one if not.

Categories

Resources