How to map through two arrays and send data as props to other component? I want to send data from price and gamedet as a prop to Wishlist Component.As I am new to react, suggest me if this code is not good or unclean too, thanks in advance.
This is the dumb way I send whole array to Wishlist component :
price.map((game1) => {
let temp = {
steamAppID: game1.steamAppID,
storeID: game1.storeID,
normalPrice: game1.normalPrice,
salePrice: game1.salePrice,
};
console.log("temp sale", temp.salePrice);
return tempArr1.push(temp) && tempArr2.push(temp.steamAppID));
})
This is all of WishListData component:
import React, { useEffect, useState } from "react";
import Wishlist from "./Wishlist";
import "./Wishlist.css";
import "animate.css";
import axios from "axios";
const WishlistData = () => {
const [gamedet, setGameDet] = useState([]);
const [loaded, setLoaded] = useState(false);
const [stores, setStores] = useState([]);
const [price, setPrice] = useState([]);
const [wishlist, setWishlist] = useState([]);
useEffect(() => {
setWishlist(
localStorage.getItem("Wishlist")
? JSON.parse(localStorage.getItem("Wishlist"))
: []
);
}, []);
const RemoveFromWishlist = (id) => {
let newList = wishlist.filter((game) => game.gameID !== id);
setWishlist(newList)
localStorage.setItem("Wishlist", JSON.stringify(newList));
console.log("id", [wishlist.pop(id)]);
console.log("newlist", wishlist);
setGameDet([])
};
const DET_URL = `https://api.rawg.io/api/games`;
useEffect(() => {
let isCancelled = false;
const RAWGdet = () => {
wishlist &&
wishlist.map(async (game, index) => {
const res = await axios({
url: `https://cors-anywhere.herokuapp.com/${DET_URL}/${game.gameID}?key=${process.env.REACT_APP_RAWG_KEY}`,
headers: {
"X-Requested-With": "XMLHttpRequest",
},
method: "GET",
});
if (!isCancelled) {
setGameDet((gamedet) => gamedet.concat(res.data));
}
setLoaded(true);
});
};
RAWGdet();
return () => {
isCancelled = true;
};
}, [DET_URL, wishlist]);
useEffect(() => {
let isCancelled = false;
const CSPrice = () => {
wishlist &&
wishlist.map(async (game, index) => {
const res = await axios({
url: `https://cors-anywhere.herokuapp.com/${DET_URL}/${game.slug}/stores?key=${process.env.REACT_APP_RAWG_KEY}`,
headers: {
"X-Requested-With": "XMLHttpRequest",
},
method: "GET",
});
if (!isCancelled) {
setStores((stores) => stores.concat(res.data));
}
setLoaded(true);
});
};
CSPrice();
return () => {
isCancelled = true;
};
}, [DET_URL, wishlist]);
let stm = [];
stores
.map((steam) => {
return steam.results;
})
.filter((item) => {
return item.map((id) => {
return id.store_id === 1 ? stm.push(id.url) : <>{null}</>;
});
});
let idmain = [];
stm.map((steamid) => {
return steamid.split("/").map((item) => {
return idmain.push(item);
});
});
useEffect(() => {
let isCancelled = false
wishlist.length !==0 &&
wishlist.map((game, index) => {
return (
<div key={index}>
{axios
.get(
`https://www.cheapshark.com/api/1.0/deals?storeID=1&steamAppID=${game.steamID}`
)
.then((res) => {
if (!isCancelled){
setPrice((price) => price.concat(res.data));
setLoaded(true)
}
})
.catch((err) => {
console.log("ERR", err);
})}
</div>
);
});
return () => {
isCancelled = true
}
}, [wishlist]);
let tempArr1 = [];
let tempArr2 = [];
if (loaded ) {
return (
<div className="animate__animated animate__slideInDown">
<div className="wishlist_header">
<h3>Your Wishlist</h3>
</div>
{wishlist.length !== 0 ? (
price.map((game1) => {
let temp = {
steamAppID: game1.steamAppID,
storeID: game1.storeID,
normalPrice: game1.normalPrice,
salePrice: game1.salePrice,
};
console.log("temp sale", temp.salePrice);
return tempArr1.push(temp) && tempArr2.push(temp.steamAppID));
}) &&
gamedet.map((game, index) => {
// console.log("mad2", game.name);
return (
<div id="wishlist_ctn" key={index}>
<Wishlist
// key={index}
title={game.name}
steamRatingCount={game.id}
// steamRatingPercent={game[0].steamRatingPercent}
// savings={game[0].savings}
// normalPrice={}
// salePrice={salePrice}
steamAppID={tempArr2}
data={tempArr1}
image={game.background_image}
rem={() => RemoveFromWishlist(game.id)}
/>
</div>
);
})
) : (
<div className="wishlist_header">
<h3>Add Games!!</h3>
</div>
)}
</div>
);
} else {
return (
<div className="hmm">
<div className="wishlist_header">
<h3>Your Wishlist</h3>
</div>
<div className="wishlist_header">
<h3>Loading Games</h3>
</div>
);
</div>
);
}
};
export default WishlistData;
I don't understand why you need two extra arrays since you are mapping price to populate
tempArr1, which contain a copy of its items, and tempArr2, which contains a copy of its steamAppIDs.
I think you could just pass the price array as data, and a mapped version as steamAppID:
{wishlist.length !== 0 ?
(gamedet.map((game, index) => {
<Wishlist
// key={index}
title={game.name}
steamRatingCount={game.id}
// steamRatingPercent={game[0].steamRatingPercent}
// savings={game[0].savings}
// normalPrice={}
// salePrice={salePrice}
steamAppID={price.map(item => item.steamAppID)}
data={price}
image={game.background_image}
rem={() => RemoveFromWishlist(game.id)}
/>;
</div>
);
})
) : (
<div className="wishlist_header">
<h3>Add Games!!</h3>
</div>
)}
Related
I have the following arrays iterated and I'm able to console.log the result I want.
import React from 'react';
const MyApplications = ({ currentUser, jobs, jobApplications }) => {
const jobAppsFromCurrentUser = jobApplications.filter(jobApp => jobApp.musician_id === currentUser.id)
return (
<div>
<div>
{
jobs.filter(job => {
jobAppsFromCurrentUser.map(jobApp => {
if (jobApp.job_id === job.id) {
console.log(job)
}
})
})
}
</div>
</div>
)
}
export default MyApplications
Result:
But ultimately, I need to render each job as jsx. I want to be able to do something like this (this doesn't return anything):
<div>
{
jobs.filter(job => {
jobAppsFromCurrentUser.map(jobApp => {
if (jobApp.job_id === job.id) {
return (
<div>
<h1>{job.title}</h1>
</div>
)
}
})
})
}
</div>
Solution:
import React from 'react';
const MyApplications = ({ currentUser, jobs, jobApplications }) => {
const jobAppsFromCurrentUser = jobApplications.filter(jobApp => jobApp.musician_id === currentUser.id)
const includesID = (id) => {
const onFilter = jobAppsFromCurrentUser.filter((jobApp) => jobApp.job_id == id);
return onFilter.length > 0 ? true : false;
};
return (
<div>
<div>
{jobs.map((job) => {
if (includesID(job.id)) {
return (
<div key={job.id}>
<h1>{job.title}</h1>
</div>
);
}
})}
</div>
</div>
)
}
export default MyApplications
First check if the ID's match.
const includesID = (id) => {
const onFilter = jobs.filter((item) => item.id == id);
return onFilter.length > 0 ? true : false;
};
And render it as
<div>
{jobAppsFromCurrentUser.map((jobApp) => {
if (includesID(jobApp.id)) {
return (
<div>
<h1>{job.title}</h1>
</div>
);
}
})}
</div>
I am building a chat app and using graphQl-ws and Im having issues with a function firing multiple times. My problem is why does doSubscriptionAction fire repeatedly and how to prevent that.
component
const ChatRooms = ({ selectConvo }: SelectConvoProp) => {
const {
data: { _id },
} = auth.getUser();
const { subscribeToMore, data } = useQuery(QUERY_CONVOS);
return (
<div className="sb-convos-wrapper">
<h3 className="sb-title">Chat Rooms - {data?.convos?.length}</h3>
<Convos
convos={data?.convos}
selectConvo={selectConvo}
subscribeToConvos={() => {
subscribeToMore({
document: SUBSCRIBE_CONVOS,
variables: { _id: _id },
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
return doSubscriptionAction(prev, { subscriptionData });
},
});
}}
/>
</div>
);
};
subscribeToMoreActions function
/// this function take the subscription payload and adds it to the prev query cache
const addToPrev = (prev: any, { subscriptionData }: any) => {
const newConvo = subscriptionData.data.convo;
const updatedConvos = Object.assign(
{},
{
convos: [...prev.convos, newConvo],
}
);
return updatedConvos;
};
const removeFromPrev = (prev: any, { subscriptionData }: any) => {
const deletedConvo = subscriptionData.data.convo;
const filteredConvos = prev.convos.filter(
(convo: any) => convo._id === deletedConvo._id
);
const updatedConvos = Object.assign(
{},
{
convos: [...filteredConvos],
}
);
console.log(updatedConvos);
return updatedConvos;
};
/// this function delegates which function to use based off action
export const doSubscriptionAction = (prev: any, { subscriptionData }: any) => {
if (subscriptionData.data.convo.action === "create") {
return addToPrev(prev, { subscriptionData });
}
if (subscriptionData.data.convo.action === "delete") {
return removeFromPrev(prev, { subscriptionData });
}
};
convos component
const Convos = ({ convos, selectConvo, subscribeToConvos }: ConvosProp) => {
useEffect(() => {
subscribeToConvos();
}, [subscribeToConvos]);
const [deleteConvo] = useMutation(DELETE_CONVO, {
refetchQueries: [{ query: QUERY_CONVOS }, "Convos"],
});
const handleDelete = async (_id: string) => {
await deleteConvo({ variables: { _id } });
};
return (
<div className="sb-chat-container">
{convos?.map((convo: ConvoType, i: number) => {
return (
<div className="sb-chat-item-container" key={`chatRoom ${i}`}>
<div
className="sb-chat-content-container"
onClick={() => selectConvo(convo)}
>
<div className={"sb-chat-content-container-top"}>
<h5>{convo.roomName}</h5>
</div>
<LastMessage convo={convo} />
</div>
<button onClick={() => handleDelete(convo._id)}>X</button>
</div>
);
})}
</div>
);
};
TLDR: doSubscriptionAction fires multiple times adding multiple instances of created room to other user.
I am building a clone of the Google Keep app with react js. I added all the basic functionality (expand the create area, add a note, delete it) but I can't seem to manage the edit part. Currently I am able to edit the inputs and store the values in the state, but how can I replace the initial input values for the new values that I type on the input?
This is Note component
export default function Note(props) {
const [editNote, setEditNote] = useState(false);
const [currentNote, setCurrentNote] = useState({
id: props.id,
editTitle: props.title,
editContent: props.content,
});
const handleDelete = () => {
props.deleteNote(props.id);
};
const handleEdit = () => {
setEditNote(true);
setCurrentNote((prevValue) => ({ ...prevValue }));
};
const handleInputEdit = (event) => {
const { name, value } = event.target;
setCurrentNote((prevValue) => ({
...prevValue,
[name]: value,
}));
};
const updateNote = () => {
setCurrentNote((prevValue, id) => {
if (currentNote.id === id) {
props.title = currentNote.editTitle;
props.content = currentNote.editContent;
} else {
return { ...prevValue };
}
});
setEditNote(false);
};
return (
<div>
{editNote ? (
<div className='note'>
<input
type='text'
name='edittitle'
defaultValue={currentNote.editTitle}
onChange={handleInputEdit}
className='edit-input'
/>
<textarea
name='editcontent'
defaultValue={currentNote.editContent}
row='1'
onChange={handleInputEdit}
className='edit-input'
/>
<button onClick={() => setEditNote(false)}>Cancel</button>
<button onClick={updateNote}>Save</button>
</div>
) : (
<div className='note' onDoubleClick={handleEdit}>
<h1>{props.title}</h1>
<p>{props.content}</p>
<button onClick={handleDelete}>DELETE</button>
</div>
)}
</div>
);
}
And this is the Container component where I am renderind the CreateArea and mapping the notes I create. I tried to map the notes again with the new values but it wasn't working.
export default function Container() {
const [notes, setNotes] = useState([]);
const addNote = (newNote) => {
setNotes((prevNotes) => {
return [...prevNotes, newNote];
});
};
const deleteNote = (id) => {
setNotes((prevNotes) => {
return prevNotes.filter((note, index) => {
return index !== id;
});
});
};
// const handleUpdateNote = (id, updatedNote) => {
// const updatedItem = notes.map((note, index) => {
// return index === id ? updatedNote : note;
// });
// setNotes(updatedItem);
// };
return (
<div>
<CreateArea addNote={addNote} />
{notes.map((note, index) => {
return (
<Note
key={index}
id={index}
title={note.title}
content={note.content}
deleteNote={deleteNote}
//handleUpdateNote={handleUpdateNote}
/>
);
})}
</div>
);
}
There are a couple of mistakes in your code.
The state properties are in the camel case
const [currentNote, setCurrentNote] = useState({
...
editTitle: props.title,
editContent: props.content,
});
But the names of the input are in lowercase.
<input
name='edittitle'
...
/>
<textarea
name='editcontent'
...
/>
Thus in handleInputEdit you don't update the state but add new properties: edittitle and editcontent. Change the names to the camel case.
In React you cant assign to the component prop values, they are read-only.
const updateNote = () => {
...
props.title = currentNote.editTitle;
props.content = currentNote.editContent;
You need to use the handleUpdateNote function passed by the parent component instead. You have it commented for some reason.
<Note
...
//handleUpdateNote={handleUpdateNote}
/>
Check the code below. I think it does what you need.
function Note({ id, title, content, handleUpdateNote, deleteNote }) {
const [editNote, setEditNote] = React.useState(false);
const [currentNote, setCurrentNote] = React.useState({
id,
editTitle: title,
editContent: content,
});
const handleDelete = () => {
deleteNote(id);
};
const handleEdit = () => {
setEditNote(true);
setCurrentNote((prevValue) => ({ ...prevValue }));
};
const handleInputEdit = (event) => {
const { name, value } = event.target;
setCurrentNote((prevValue) => ({
...prevValue,
[name]: value,
}));
};
const updateNote = () => {
handleUpdateNote({
id: currentNote.id,
title: currentNote.editTitle,
content: currentNote.editContent
});
setEditNote(false);
};
return (
<div>
{editNote ? (
<div className='note'>
<input
type='text'
name='editTitle'
defaultValue={currentNote.editTitle}
onChange={handleInputEdit}
className='edit-input'
/>
<textarea
name='editContent'
defaultValue={currentNote.editContent}
row='1'
onChange={handleInputEdit}
className='edit-input'
/>
<button onClick={() => setEditNote(false)}>Cancel</button>
<button onClick={updateNote}>Save</button>
</div>
) : (
<div className='note' onDoubleClick={handleEdit}>
<h1>{title}</h1>
<p>{content}</p>
<button onClick={handleDelete}>DELETE</button>
</div>
)}
</div>
);
}
function CreateArea() {
return null;
}
function Container() {
const [notes, setNotes] = React.useState([
{ title: 'Words', content: 'hello, bye' },
{ title: 'Food', content: 'milk, cheese' }
]);
const addNote = (newNote) => {
setNotes((prevNotes) => {
return [...prevNotes, newNote];
});
};
const deleteNote = (id) => {
setNotes((prevNotes) => {
return prevNotes.filter((note, index) => {
return index !== id;
});
});
};
const handleUpdateNote = ({ id, title, content }) => {
const _notes = [];
for (let i = 0; i < notes.length; i++) {
if (i === id) {
_notes.push({ id, title, content });
} else {
_notes.push(notes[i]);
}
}
setNotes(_notes);
};
return (
<div>
<CreateArea addNote={addNote} />
{notes.map((note, index) => {
return (
<Note
key={index}
id={index}
title={note.title}
content={note.content}
deleteNote={deleteNote}
handleUpdateNote={handleUpdateNote}
/>
);
})}
</div>
);
}
function App() {
return (
<div>
<Container />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
Also, you can store the notes in an object or hash map instead of an array. For example
const [notes, setNotes] = React.useState({
'unique_id': { title: 'Words', content: 'hello, bye' }
});
Then in handleUpdateNote you have
setNotes((prev) => ({ ...prev, unique_id: { title, content } }))
I'm new to the react and I would like to know I made a function that makes filtering depending on the boolean values
let [filterState, setFilterSTate] = useState("all");
let filteredUser = todos.filter((е) => {
if (filterState === "active") {
return !е.done;
}
if (filterState === "completed") {
return е.done;
}
return true;
});
in the console, everything is displayed, but I can't figure out how to make it work in the browser itself and only the necessary tricks are displayed
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./index.css";
const TodoList = () => {
const [newTodo, setNewTodo] = useState("");
const [todos, setTodos] = useState([
{ done: true, text: "Hey", id: 1 },
{ done: false, text: "There", id: 2 },
{ done: false, text: "Dima", id: 3 },
]);
const [id, setId] = useState(4);
const toggleDone = (id) => {
setTodos(
todos.map((todo) => ({
...todo,
done: id === todo.id ? !todo.done : todo.done,
}))
);
};
const updateTodo = (id, e) => {
setTodos(
todos.map((todo) => ({
...todo,
text: id === todo.id ? e.target.value : todo.text,
}))
);
};
const onDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
const updateNewTodo = (e) => {
setNewTodo(e.target.value);
};
const onAdd = () => {
setTodos([
...todos,
{
text: newTodo,
done: false,
id,
},
]);
setId(id + 1);
setNewTodo("");
};
let [filterState, setFilterSTate] = useState("all");
let filteredUser = todos.filter((е) => {
if (filterState === "active") {
return !е.done;
}
if (filterState === "completed") {
return е.done;
}
return true;
});
// let filteredComplited = todos.filter(function (e) {
// return e.done === true;
// });
// console.log("filteredComplited", filteredComplited);
// let filteredActive = todos.filter(function (e) {
// return e.done === false;
// });
// console.log("filteredActive", filteredActive);
// let filteredAll = todos;
// console.log("filteredAll", filteredAll);
return (
<div className="todos">
Todo List
{todos.map((todo) => (
<div key={todo.id} className="todo">
<input
type="checkbox"
value={todo.done}
onChange={() => toggleDone(todo.id)}
/>
<input
type="text"
value={todo.text}
onChange={(evt) => updateTodo(todo.id, evt)}
/>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</div>
))}
<div className="todo">
<input type="text" value={newTodo} onChange={updateNewTodo} />
<button onClick={() => onAdd()}>Add</button>
</div>
<button
onclick={() =>
todos.map((t) => `${t.done ? "x" : ""} ${t.text}`).join("\n")
}
>
Save
</button>
<button onClick={() => setFilterSTate("completed")}>Complited</button>
<button onClick={() => setFilterSTate("active")}>Active</button>
<button onClick={() => setFilterSTate("all")}>All</button>
<pre>filterState: {JSON.stringify(filterState, null, 2)}</pre>
<br />
<pre>{JSON.stringify(filteredUser, null, 2)}</pre>
</div>
);
};
ReactDOM.render(<TodoList />, document.getElementById("todos"));
I am doing a React JS Cart and I am having problems when I try to delete an Item from the there. It has already a function that adds the items and also another for the total quantity and the total price.
This is the ContextProvider:
import { useState } from "react";
import { CartContext } from "./CartContext";
export const CartProvider = ({ children }) => {
const [list, setList] = useState([]);
const addCart = (varietalCount) => {
if (list.find((item) => item.id === varietalCount.id)) {
const newVarietal = list.map((varietal) => {
if (varietal.id === varietalCount.id) {
return { ...varietal, count: varietalCount.count + varietal.count };
}
return varietal;
});
setList(newVarietal);
} else {
setList((state) => {
return [...state, varietalCount];
});
}
};
console.log("list", list);
// const deleteProd = (varietalCount) => {
// if (list.find((item) => item.id === varietalCount.id)) {
// const deleteVarietal = list.map((varietal) => {
// if (varietal.id === varietalCount.id) {
// return { ...varietal, count: null };
// }
// return varietal;
// });
// setList(deleteVarietal);
// } else {
// setList((state) => {
// return [...state, varietalCount];
// });
// }
// };
const totalPrice = () => {
return list.reduce((prev, next) => (prev + (next.count * next.price)), 0)
};
const totalQuantity = () => {
return list.reduce((prev, next) => (prev + (next.count)), 0)
};
return(
<>
<CartContext.Provider value={{ list, addCart, totalPrice, totalQuantity }}>
{children}
</CartContext.Provider>
</>);
};
If it is necessary I can add to the post the Cart.js or the ItemDetail.js. I hope someone can help me. Cheers
I think you can just use filter given that your state has value of an array. Something like:
const deleteProd = (varietalCount) => {
const newItems = list.filter((item) => item.id !== varietalCount.id)
setList(newItems);
};
You can check more array functions from here https://www.w3schools.com/jsref/jsref_obj_array.asp