Adding duplicates into array - javascript

I would like to be able to sort my array so I don't have duplicates into my "Recently-Viewed" section. The recently viewed section works fine except that it breaks when I add a duplicate. So I want to be able to sort my array so it doesn't break. I'm not really sure how to implement a sort function. Do I use filter or what do I do? I'm really confused.
My code:
const [tvShow, setTVShow] = useState([]);
const [recentlyViewed, setRecentlyViewed] = useState([]);
const getMovieRequest = async () => {
const url = `https://api.themoviedb.org/3/movie/top_rated?api_key=1e08baad3bc3eca3efdd54a0c80111b9&language=en-US&page=1`;
const response = await fetch(url);
const responseJson = await response.json();
setTVShow(responseJson.results)
};
useEffect(() => {
getMovieRequest();
},[]);
useEffect(() => {
const recentlyMovies = JSON.parse(localStorage.getItem('react-movie-app-favourites')
);
if (recentlyMovies) {
setRecentlyViewed(recentlyMovies.slice(0,5));
}
}, []);
const saveToLocalStorage = (items) => {
localStorage.setItem('react-movie-app-favourites', JSON.stringify(items))
};
const addRecentlyViewed = (movie) => {
const newRecentlyViewed = [movie, ...recentlyViewed]
setRecentlyViewed(newRecentlyViewed.slice(0,5));
saveToLocalStorage(newRecentlyViewed);
if (newRecentlyViewed > 5) {
newRecentlyViewed.pop();
}
};
Thank you guys in advance. I'm new to React and I find this very confusing.

Using the Set constructor and the spread syntax:
uniq = [...new Set(array)];
useEffect(() => {
const recentlyMovies = [...new Set(JSON.parse(localStorage.getItem('react-movie-app-favourites')))];
if (recentlyMovies) {
setRecentlyViewed(recentlyMovies.slice(0,5));
}
}, []);

Related

Get firestore data as array

Im tryng to display firestore data but I just get one value. I have try forEach and map. Nothing is working. Heres my code:
React.useEffect(() => {
retrieveNetwork();
}, []);
const retrieveNetwork = async () => {
try {
const q = query(collection(db, "cities", uidx, "adress"));
const querySnapshot = await getDocs(q);
let result = [];
//querySnapshot.docs.map((doc) => setGas(doc.data().home));
querySnapshot.docs.map((doc) => {
result.push(doc.data().home);
setGas(result);
});
} catch (e) {
alert(e);
}
};```
The .map method returns an array (official docs here), so you could do something like this:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
React.useEffect(() => {
retrieveNetwork();
}, []);
const retrieveNetwork = async () => {
try {
const q = query(collection(db, "cities", uidx, "adress"));
const querySnapshot = await getDocs(q);
// an array from the docs filled only with "home" data
const results = querySnapshot.docs.map((doc) => {
return doc.data().home;
});
// only update the state once per invokation
setGas(results)
} catch (e) {
alert(e);
}
};

after updated array list not index instantly -react.js

i need a filter with time "old to new" and "new to old"
here is my code template:
const timeNewToOld = () => {
const [paginationUsers,setPaginationUsers] = useState([])
const newToOld = users.sort((a, b) => {
return b.Time.localeCompare(a.Time)
})
setPaginationUsers(newToOld)
}
const timeOldToNew = () => {
const oldToNew = users.sort((a, b) => {
return a.Time.localeCompare(b.Time)
})
setPaginationUsers(oldToNew)
}
this functions working but, not responding instantly on web browser.
i hope i can explain with these images:
i click on the "newtoold" function and nothing changes:
i move to the next page and i'm back to the 1st page:
everything is fine. only the first time I click on the function, it doesn't get instant updates, when I change the page, the index returns to normal.
paginationUsers created here:
useEffect(() => {
const getAllData = async () => {
onSnapshot(_dbRef, (snapshot) => {
const data = snapshot.docs.map((doc) => {
return {
id: doc.id,
...doc.data(),
}
})
setUsers(data)
setUserPageCount(Math.ceil(data.length / 20))
})
}
getAllData()
}, [])
useEffect(() => {
displayUsers(users, setPaginationUsers, userCurrentPage)
}, [users, setPaginationUsers, userCurrentPage])
i hope i could explain,
happy coding..
Array.prototype.sort doesn't create a new array, so react can't know that it changed. Creating a new array should help.
const timeOldToNew = () => {
const oldToNew = [...users].sort((a, b) => {
return a.Time.localeCompare(b.Time)
})
setPaginationUsers(oldToNew)
}

Fetch data from huge amount fetched URLs

Not sure how to go about this.
I fetch from 1 URL to get an array of objects like this:
[{name: 'apple', url: 'appleURL'}, {name: 'orange', 'orangeURL', ...}]
then map through each URL to fetch data, the returned data for each item has another URL... like this:
[{name: 'apple', colors: ['green', 'red'], type: 'http://URL-that-needs-fetching'},{...etc}]
heres what i have, and it works but it's extremely slow...
useEffect(() => {
const fetchFruit = async () => {
setLoading(true);
const fruitResponse = await fetch(fruitPath);
const fruitJson: Fruit =
await fruitResponse.json();
const fruitDetails = await Promise.all(
fruitJson.results.map(async (f: FruitURLs) => {
const fDetails = await fetch(f.url);
const json: FruitDetails = await fDetails.json();
return json;
})
);
const getFruitDescriptions = await Promise.all(
fruitDetails.map(async (item: FruitDetails, index: number) => {
const fruitType = await fetch(item.type.url);
const json: FruitInfo = await fruitType.json();
return json;
})
);
let full: FruitDetails[] = fruitDetails;
for (let index = 0; index < fruitDetails.length; index++) {
full[index].fruitInfo = getFruitDescriptions[index];
}
setFruitDetails(full);
setLoading(false);
};
fetchFruit();
}, []);
I'm new to using promises and not 100% confident with them, also new to TS, and react-native so apologies if there's mistakes here....
The problem is that by using await inside Promise.all(), you are resolving the fetches instead of having them happen in parallel and returning it wrapped by a promise.
You can take a reference:
const fetchFruit = async () => {
const fruitResponse = await fetch(fruitPath);
const fruitJson: Fruit = await fruitResponse.json();
const fruitDetails = await Promise.all(
fruitJson.results.map(async (f: FruitURLs) => fetch(f.url))
);
const getFruitDescriptions = await Promise.all(
fruitDetails.map(async (item: FruitDetails, index: number) =>
fetch(item.type.url)
)
);
const [fruitDetailsAsJson, getFruitDescriptionsAsJson] = Promise.all([
fruitDetails.map(async (f) => f.json()),
getFruitDescriptions.map(async (f) => f.json()),
]);
const full = fruitDetailsAsJson.map((fruit, index) => ({
...fruit,
fruitInfo: getFruitDescriptionsAsJson[index],
}));
setFruitDetails(full);
setLoading(false);
};
Use this resource to learn about the best practice.
If there are a lot of entries in the fruitresponse, and the back end cannot aggregate all the data, then it is inevitable to be slow. At this time, we should consider loading a little and displaying a little
const FruitList = ()=> {
const { data, loading } = useFetch(fruitPath);
if (loading) return <div>Loading...</div>
return data.results.map(x=> <Fruit key={x.id} data={x} />)
}
const Fruit = ({data}: { data: FruitDetails })=> {
const { data, loading } = useFetch(data.url);
if (loading) return <div>Loading...</div>;
return (
<div>
{data.name}
<FruitDescription url={data.type.url} />
</div>
)
}
const FruitDescription = ({url}: { url: string })=> {
const { data, loading } = useFetch(url);
if (loading) return <div>Loading...</div>;
return <div>{data.description}</div>
}

How to optimally combine multiple axios responses

I am working with a React app. I have to create 2 objects using responses from 3 different APIs. For example:
DataObject1 will be created using API1 and API2
DataObject2 will be created using API1, API2, and API3
So, I am thinking about what would be the most optimal way of doing this by making sure 1 call each API only once.
I was thinking this:
const requestOne = axios.get(API1);
const requestTwo = axios.get(API2);
const requestThree = axios.get(API3);
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((...responses) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
})).catch(errors => {
// react on errors.
})
const createDataObject1 = (response1, response2) => { //Combine required data and return dataObject1 }
const createDataObject2 = (response1, response2, response3) => { //Combine required data and return dataObject2 }
Is there a better way of doing this?
Looks fine.
You can change this
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((...responses) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
})).catch(errors => {
// react on errors.
})
to
axios.all([requestOne, requestTwo, requestThree]).then((response) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
}).catch(errors => {
// react on errors.
})
because it is unnecessary to spread and rest.
If you don't want to use them like responses[0], responses[1], etc then you can use:
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((response1, response2, response3) => {
const dataObject1 = createDataObject1(response1, response2);
const dataObject2 = createDataObject2(response1, response2,response3);
// use/access the results
})).catch(errors => {
// react on errors.
})
Are you using thunk middleware to make async calls in Redux? I don't want to assume that you are, but that seems like a good basic approach here.
const requestOne = axios.get(API1);
const requestTwo = axios.get(API2);
const requestThree = axios.get(API3);
Okay. So now requestOne.data has the result of making the axios get request. Or, would if the thunk creator was async and the code was const requestOne = await axios.get(API1);
Do you need to parse the data further from request___.data ?
If not you can just have
const dataObj1 = { response1: requestOne.data, response2: requestTwo.data }
const dataObj2 = { ... dataObject1, response3: requestThree.data };
Full answer:
// store/yourFile.js code
export const YourThunkCreator = () => async dispatch => {
try {
const const requestOne = await axios.get(API1);
// other axios requests
const dataObj1 = { response1: requestOne.data, response2: requestTwo.data }
const dataObj2 = { ... dataObject1, response3: requestThree.data };
// other code
dispatch(// to Redux Store);
} catch (error) {
console.error(error);
}

How to fetch data from multiple urls at once?

I have a function that fetches from a url in React
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
useEffect(() => {
const fetchCocktailList = async () => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
setLoading(true);
try {
const res = await fetch(`${baseUrl}search.php?s=margarita`);
const data = await res.json();
console.log(data);
setCocktails(data.drinks);
setLoading(false);
} catch (err) {
console.log('Error fetching data');
setLoading(false);
}
};
fetchCocktailList();
}, []);
How I'm mapping data so far.
const DrinkList = () => {
const { cocktails } = useContext(DataContext);
return (
<div className='drink-list-wrapper'>
{cocktails.length > 0 &&
cocktails.map((drink) => {
return <DrinkItem drink={drink} key={drink.idDrink} />;
})}
</div>
);
};
However I want to fetch from this url also ${baseUrl}search.php?s=martini
I would like a good clean way to do this and set my state to both of the returned data.
First base the data fetch function on a parameter:
const fetchCocktail = async (name) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
try {
const res = await fetch(`${baseUrl}search.php?s=` + name);
const data = await res.json();
return data.drinks;
} catch (err) {
console.log('Error fetching data');
}
}
Then use Promise.all to await all results:
setLoading(true);
var promises = [
fetchCocktail(`margarita`),
fetchCocktail(`martini`)
];
var results = await Promise.all(promises);
setLoading(false);
DrinkList(results);
Where results will be an array with the responses that you can use on the DrinkList function.
Here's a method which will let you specify the cocktail names as dependencies to the useEffect so you can store them in your state and fetch new drink lists if you want new recipes. If not, it'll just be a static state variable.
I've also added another state variable errorMessage which you use to pass an error message in the case of failure.
Also, you should include the appropriate dependencies in your useEffect hook. The setState functions returned by calls to useState are stable and won't trigger a re-run of the effect, and the cocktailNames variable won't trigger a re-run unless you update it with new things to fetch.
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
const [errorMessage, setErrorMessage] = useState(''); // holds an error message in case the network request dosn't succeed
const [cocktailNames, setCocktailNames] = useState(['margarita', 'martini']); // the search queries for the `s` parameter at your API endpoint
useEffect(() => {
const fetchCocktailLists = async (...cocktailNames) => {
const fetchCocktailList = async (cocktailName) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/search.php';
const url = new URL(baseUrl);
const params = new URLSearchParams({s: cocktailName});
url.search = params.toString(); // -> '?s=cocktailName'
const res = await fetch(url.href); // -> 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=cocktailName'
const data = await res.json();
const {drinks: drinkList} = data; // destructured form of: const drinkList = data.drinks;
return drinkList;
};
setLoading(true);
try {
const promises = [];
for (const cocktailName of cocktailNames) {
promises.push(fetchCocktailList(cocktailName));
}
const drinkLists = await Promise.all(promises); // -> [[drink1, drink2], [drink3, drink4]]
const allDrinks = drinkLists.flat(1); // -> [drink1, drink2, drink3, drink4]
setCocktails(allDrinks);
}
catch (err) {
setErrorMessage(err.message /* or whatever custom message you want */);
}
setLoading(false);
};
fetchCocktailList(...cocktailNames);
}, [cocktailNames, setCocktails, setErrorMessage, setLoading]);
};
var promises = [
fetchCocktail(api1),
fetchCocktail(api2)
];
var results = await Promise.allSettled(promises);

Categories