how can I delete the element in react js - javascript

I want to create simple application with react js, which should show the users in the display and then when I click on the delete button, it should delete the following item, however I am having some errors.
import React, { useEffect, useState } from 'react'
const App = () => {
const [users, setUsers] = useState([])
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
setUsers(users);
})
}, [users]);
const deleteMe = () => {
setUsers(prevState => {
return prevState.filter(e => e.name)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={deleteMe}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
}
export default App

To remove the user, the callback (onClick) must have enough information to identify the user to be removed.
In this example, you have some options:
Remove by name. Only if the user names are unique:
const deleteMe = (userName) => {
setUsers(prevState => {
return prevState.filter(e => e.name !== userName)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(user.name)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
Remove by the element itself. Only if the element isn't repeated in the array (the object itself):
const deleteMe = (user) => {
setUsers(prevState => {
return prevState.filter(e => e !== user)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(user)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
Remove by the array index. Only if the state is an array, usually:
const deleteMe = (userIndex) => {
setUsers(prevState => {
return prevState.filter((e, i) => i !== userIndex)
})
}
return (
<>
{users.map((user, i) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(i)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
See how a second parameter i was added to the map and filter functions. That is usually ignored, but it may be useful sometimes.
As this method may fail if the array is reordered of an element is added/removed between the render and the callback, I wouldn't recommend it unless there is no other alternative.

Look at the useEffect code. Because you have users as a dependency the effect will pick up any changes to that state. State changes, you make an API call, then update users, the effect gets called again on the next render, you update users in state, users gets updated again... etc.
It sounds like you just need an empty dependency array so that the effect is only called once when the component is rendered.
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
setUsers(users);
})
}, []);

try this , element get deleted and not refresh
import React, { useEffect, useState } from 'react';
const Example = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
// .then()
// .then(users => {
// setUsers(users);
// });
};
const deleteMe = index => {
setUsers(prevState => {
console.log(prevState);
return prevState.filter((e, i) => i !== index);
});
};
return (
<div>
{users.map((user, i) => {
return (
<div>
{' '}
{user.name}
<button onClick={() => deleteMe(i)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
);
})}
</div>
);
};
export default Example;

Related

Warning: Cannot update a component (`Home`) while rendering a different component (`Posts`). To locate the bad setState() call inside `Posts`,

Problem: when i click on the button
<button
onClick={() => {
navigate('/posts');
setResponse(e.id);
}}
>
I get this error: Warning: Cannot update a component (Home) while rendering...
I think problem only in this line
navigate('/posts');
because if I delete it, error disappears
full code under without import
App.js
function App() {
const [response, setResponse] = useState({});
return (
<Router>
<Routes>
<Route exact path="/" element={<Home setResponse={setResponse} />} />
<Route exact path="/posts" element={<Posts response={response} />} />
<Route exact path="*" />
</Routes>
</Router>
);
}
export default App;
Home.js
function Home({ setResponse }) {
const [modal, setModal] = useState(false);
const navigate = useNavigate();
const dispatch = useDispatch();
const state = useSelector((state) => state);
console.log(state);
if (state.user.isLoading) {
return <h1>Loading...</h1>;
}
const toggleModal = () => {
setModal(!modal);
};
return (
<div className="App">
<button onClick={(e) => dispatch(fetchUsers())}>Fetch users</button>
{state.user.data &&
state.user.data.map((e) => (
<div key={e.id}>
<li key={e.name}>{e.name}</li>
<button
key={e.id + 10}
onClick={() => {
navigate('/posts');
setResponse(e.id);
}}
className="btn"
>
Posts
</button>
<button onClick={toggleModal} key={e.id + 100} className="bnt">
Albums
</button>
</div>
))}
<Albums modal={modal} setModal={setModal} />
</div>
);
}
export default Home;
Posts.js
function Posts({ response }) {
const dispatch = useDispatch();
const navigate = useNavigate();
const state = useSelector((state) => state);
console.log(state);
if (state.post.isLoading) {
return <h1>Loading...</h1>;
}
if (!state.post.data) {
dispatch(fetchPosts());
}
return (
<div className="App">
Posts
{state.post.data &&
state.post.data
.filter((e) => e.userId === response)
.map((e) => (
<div key={e.userId.toString() + e.id.toString()}>
<li key={e.id}>{e.title}</li>
</div>
))}
<button
onClick={() => {
navigate('/');
}}
>
List of users
</button>
</div>
);
}
export default Posts;
I tried to use useEffect(), but it doesn't work in my case
<button
onClick={() => {useEffect(()=>{
navigate('/posts');
setResponse(e.id);},[])
}}
>
If you're navigating away to another page, you shouldn't be updating the state as you're navigating (which you're doing by calling setResponse after navigate).
To fix this error, you'd have to call navigate() after React finishes updating the response variable, which you can do by using a useEffect call at the top-level of your Home component:
// you should also pass the value of response to the Home component so it knows when it's been changed
function Home({ setResponse, response }) {
const [modal, setModal] = useState(false);
const navigate = useNavigate();
const dispatch = useDispatch();
const state = useSelector((state) => state);
console.log(state);
useEffect(() => {
// This if statement checks if response === {}, which is a bit awkward; you should instead initialize your response state to a value like `null`
if (typeof response === 'object' && Object.keys(response).length === 0) {
return
}
navigate('/posts')
}, [response])
if (state.user.isLoading) {
return <h1>Loading...</h1>;
}
const toggleModal = () => {
setModal(!modal);
};
return (
<div className="App">
<button onClick={(e) => dispatch(fetchUsers())}>Fetch users</button>
{state.user.data &&
state.user.data.map((e) => (
<div key={e.id}>
<li key={e.name}>{e.name}</li>
<button
key={e.id + 10}
onClick={() => {
// navigate('/posts');
setResponse(e.id);
}}
className="btn"
>
Posts
</button>
<button onClick={toggleModal} key={e.id + 100} className="bnt">
Albums
</button>
</div>
))}
<Albums modal={modal} setModal={setModal} />
</div>
);
}
export default Home;

How to substitute values ​in a component from two arrays?

I have an array of houses that comes from Firestore, and an array of images of those houses that come from Storage. With the help of map, I go through the array of houses and supply information about it to the component. How do I iterate through an array of images and add them to a component?
const List = ({ selectedHouse }) => {
const [houseTitles, setHouseTitle] = useState([]);
const [houseImages, setHouseImages] = useState([]);
const imageListRef = ref(storage, "images/");
useEffect(() => {
const q = query(collection(db, "map-markers"));
onSnapshot(q, (querySnapshot) => {
setHouseTitle(
querySnapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
);
});
}, []);
useEffect(() => {
listAll(imageListRef).then((response) => {
response.items.forEach((item) => {
getDownloadURL(item).then((url) => {
setHouseImages((prev) => [...prev, url]);
});
});
});
}, []);
return (
<div className="list-container" style={{ width: "50%" }}>
<ListItem title={houseTitles[selectedHouse]?.data?.title} />
{houseTitles
.filter((title, index) => index !== selectedHouse)
.map((title, index) => (
<ListItem key={index} title={title?.data?.title} />
))}
</div>
);
};
const ListItem = (props) => {
return (
<div className="list-item">
<img src={props.url} alt="" />
<h2>{props.title}</h2>
</div>
);
};
I think this is the answer you are looking for:
return (
// ...
{houseTitles
.map((title, idx) => ({title, image: houseImages[idx]}))
.filter((_houseArr, idx) => idx !== selectedHouse)
.map((houseArr, idx) => (
<ListItem key={idx} title={houseArr.title?.data?.title} url={/* YOUR IMAGE SRC HERE, IS IT houseArr.image? */} />
))}
// ...
)

React Toggle Hook State

I tried to toggle individual item but unfortunately whenever I try to toggle an item the other item gets affected. Here is my code:
const FAQ = () => {
const [open, setOpen] = useState(false);
const [data, setData] = useState(faqData);
return (
<FAQSection>
<FAQTitle>Frequently Asked Questions</FAQTitle>
<Questions>
<QuestionItemDetail>
{data.map((item) => {
const { id, question, answer } = item;
return (
<div key={id}>
<QuestionItem onClick={() => setOpen(!open)}>
<QuestionItemTitle>{question}</QuestionItemTitle>
{open ? <Close /> : <Add />}
</QuestionItem>
<ReadQuestion>
{open && (
<ReadQuestionDetail>
<ReadQuestionDesc>{answer}</ReadQuestionDesc>
</ReadQuestionDetail>
)}
</ReadQuestion>
</div>
);
})}
</QuestionItemDetail>
</Questions>
</FAQSection>
);
};
What might be wrong with this because I ensured the dummy data has a unique ID.
Because you use a boolean to control all open/close. You need to use index/id to control this.
const [open, setOpen] = useState(null);
...
onClick={() => setOpen(preOpen => preOpen === id ? null : id)}
...
{open === id && (<ReadQuestionDetail>...</ReadQuestionDetail>)}
Your open state is used for all of the items in your data array, which is why it affects all of the items when toggled.
I recommend:
putting all of the data item html/jsx inside a new component.
Inside this new component, create an open state like so:
const MyItemComponent = (id, question, answer) => {
const [open, setOpen] = useState(false);
return (
<div key={id}>
<QuestionItem onClick={() => setOpen(!open)}>
<QuestionItemTitle>{question}</QuestionItemTitle>
{open ? <Close /> : <Add />}
</QuestionItem>
<ReadQuestion>
{open && (
<ReadQuestionDetail>
<ReadQuestionDesc>{answer}</ReadQuestionDesc>
</ReadQuestionDetail>
)}
</ReadQuestion>
</div>
);
}
const FAQ = () => {
const [data, setData] = useState(faqData);
return (
<FAQSection>
<FAQTitle>Frequently Asked Questions</FAQTitle>
<Questions>
<QuestionItemDetail>
{data.map((item) => {
const { id, question, answer } = item;
return (
<MyItemComponent id={id} question={question} answer={answer} />
);
})}
</QuestionItemDetail>
</Questions>
</FAQSection>
);
};
This will give you an individual open state for each item.

How to pass data from mapped objects to its parent component in React?

I'm building a shopping cart app, the app includes each item as a card component. I rendered these cards by mapping some dummy object data like this:
const Home = () => {
const dummyData = [
{
id: 1,
title: 'tshirt',
price: 10
},
{
id: 2,
title: 'coat',
price: 20
}
]
const RenderCards = () => {
return (
dummyData.map(
(d) => {
return (
<Card key={d.id} title={d.title} price={d.price} handleAddToCart={handleAddToCart}/>
)
}
)
)
}
const handleAddToCart = () => {
// maybe access id and price here?
}
return (
<>
<RenderCards />
</>
)
}
and the Card component being rendered:
const Card = ({id, title, price}) => {
return (
<>
<div key={id}>
<p>{title}</>
<p>{price}</>
<button onClick={handleAddToCart}>Add to cart</button>
</div>
</>
)
}
Now on click of the button in each card, I'd like to send the data (the id of the card and the price of the item) back to the parent Home component. Say 2nd card is clicked, I want to have access to id and price in Home.
EDIT:
Maybe I didn't make myself clear, I'd like to access the clicked card's price and id in handleAddToCart function.
You can either pass the handler down and have the child pass the details to it, like this:
items.map(item => <Item addToCart={addToCart} {...item} />)
const Item = ({ id, name, addToCart }) =>
<div>
{name}
<button onClick={() => addToCart(id)}>Add to Cart</button>
</div>
Or pass down a values-included callback like this:
items.map(item => <Item addToCart={() => handleAddToCart(item.id)} {...item} />)
const Item = ({ id, name, addToCart }) =>
<div>
{name}
<button onClick={addToCart}>Add to Cart</button>
</div>
In <Home /> component, first you can introduce a new state with useState as:
const [selectedItem, setSelectedItem] = useState(null)
Then pass down through props the setSelectedItem in order to be able to trigger there:
<Card key={d.id} title={d.title} price={d.price} handleAddToCart={handleAddToCart}
setSelectedItem={setSelectedItem} />
Then in <Card /> component use as:
const Card = ({id, title, price, setSelectedItem}) => {
return (
<>
<div key={id}>
<p>{title}</>
<p>{price}</>
<button onClick={() => {
handleAddToCart();
setSelectedItem({ id, title, price});
}}>Add to cart</button>
</div>
</>
)
}
+1 suggestion:
I would pass down to <Card /> component the details in one attribute as:
<Card key={d.id}
data={d}
handleAddToCart={handleAddToCart}
setSelectedItem={setSelectedItem} />
Then destructure inside as:
const Card = (props) => {
const { data, setSelectedItem, handleAddToCart } = props
const { id, title, price } = data
// more code
}

Setting state from another component react hooks

There a two components one is <Form /> and other is <LoginForm />.
<LoginForm /> looks like
const LoginForm = () => {
return (
<Form
inputs={[
//some objects here
]}
onSubmit={(data, setError) => {
setError('some error')
}}
/>
);
};
The <Form /> component looks like.
const Form = ({onSumbit, inputs}) => {
const [error, setError] = useState('');
return (
<>
{error ? <div>{error}</div> : null}
{//rendering inputs here}
<button onClick={() => onSubmit('some data which is not relative to problem', setError)}>
</>
)
}
Now when the button is clicked on onSubmit() should run. And it should call setError which should show some error but its not showing any error. Its also not showing any kind of error.
Note: This is only the relevant part of code. Code is actually large. But I am sure that only this part have some basic flaw.
Sometimes you declared onSumbit and sometimes onSubmit, you need to be consistent:
const LoginForm = () => {
return (
<Form
onSubmit={(data, setter) => {
setter('some error');
}}
/>
);
};
const Form = ({ onSubmit, inputs }) => {
const [error, setError] = useState('');
return (
<>
{error ? <div>{error}</div> : null}
<button
onClick={() => {
onSubmit('some data which is not relative to problem', setError);
}}
>
Submit
</button>
</>
);
};
Here is my code. It works fine. Maybe there is some typo in your code.
const Form = ({onSubmit, inputs}) => {
const [error, setError] = useState('');
return (
<>
{error ? <div>{error}</div> : null}
<button onClick={() => onSubmit('some data which is not relative to problem', setError)}>
Hi
</button>
</>
)
}
const LoginForm = () => {
return (
<Form
inputs={[
//some objects here
]}
onSubmit={(data, setError) => {
setError('some error')
}}
/>
);
};
You had typos and syntax errors previously so this couldn't have worked for you anyway.
This seems to do what you meant.
const Form = ({ onSubmit, inputs }) => {
const [error, setError] = useState('');
return (
<>
{error ? <div>{error}</div> : null}
{// rendering inputs here
}
<button onClick={() => onSubmit('data', setError)} />
</>
);
};

Categories

Resources