How to add items to the watchlist in reactJs? - javascript

I Am trying to figure out how can I add the items to watchlist,
The steps am trying to carry out here are, when a user clicks on add button, the items should be added to the watchlist page/component which I have created.
Please see the hierarchy of the component.
I would like to show added items on the watchlist page.
Please see the code I tried.
const [watchlist, setWatchlist] = useState ([]);
const handleWatchlist = (movieData) => {
const newList = [...watchlist, movieData]
setWatchlist(newList)
console.log(newList)
}
<Button className = {classes.cardButton}size = "small" onClick = { ()=> handleWatchlist(movie) }> Add </Button>
When I try to inspect, the result is, it shows the items are added but can not pass on to the watchlist component? How can use a prop to pass this value and show them?
Any help is really appreciated.
Thanks a million

The Button doesn't pass any argument in handleWatchlist in your example. I don't know how Button component looks like, but passing the arg could look like the example below:
const Button = ({ onClick }) => {
const value = "some value";
return <button onClick={() => onClick(value)}>Button</button>;
};
const WatchList = () => {
...
return <Button onClick={handleWatchlist}>Add</Button>

Thanks for the support, but I figured out the solution by using two approaches and they are
Which is props drilling, i.e. is to perform the useState action in my App.js which is my main page where I have product and watchlist component.
This is the best way I would suggest other people use as well is by using the contextAPI and useContext hooks. A simple and easy way to pass any data anywhere in the app.
Please see the full code with the working solution below on the codesandbox.
https://codesandbox.io/s/determined-nightingale-m2mtn?file=/src/components/Products
The working app, where I can add the products to the watchlist.
working demo app

Related

(Vue.js) Importing values from one component to another, not sure if it can be done with props

I'm trying to learn vue and hit a small roadbump - is there a way for me to make this work? I want to push a new value into my items array with my Button component so then i can render it with the v-for. I know it would much be easier to put everything into one file, just curious if it can be done this way. Here is the code:
https://codesandbox.io/s/mystifying-antonelli-7o6m6o?file=/src/App.vue
any help would be much appreciated :)
Sure this can be done the way you would like. One way to do it is to define the variables and the add function in the App.vue.
<script setup>
import { ref } from "vue";
const name = ref("");
const amount = ref(0);
const items = ref([]);
const addItem = () => {
items.value.push = { name: name.value, amount: amount.value };
name.value = "";
amount.value = 0;
};
</script>
Bind name and amount with your inputs via v-model and bind addItem to your button with #click. You can use items as a prop for your ItemList component.
Your components need changes to work, but I hope this will give you some direction. Perhaps first make it work with plain html input and button elements and use {{ items }} to render the items array. Once that works you can create the custom components.
Hope this helps.

React component is re-rendering items removed from state

This is a difficult one to explain so I will do my best!
My Goal
I have been learning React and decided to try build a Todo List App from scratch. I wanted to implement a "push notification" system, which when you say mark a todo as complete it will pop up in the bottom left corner saying for example "walk the dog has been updated". Then after a few seconds or so it will be removed from the UI.
Fairly simple Goal, and for the most part I have got it working... BUT... if you quickly mark a few todos as complete they will get removed from the UI and then get re-rendered back in!
I have tried as many different ways of removing items from state as I can think of and even changing where the component is pulled in etc.
This is probably a noobie question, but I am still learning!
Here is a link to a code sandbox, best way I could think of to show where I am at:
Alert Component State/Parent
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/layout/PageContainer.js
Alert Component
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/parts/Alert.js
Any help much appreciated!
When you call a set function to update state, it will update from the last rendered value. If you want it to update from the last set value, you need to pass the update function instead of just the new values.
For instance, you can change your setTodos in your markComplete function to something like this.
setTodos(todos => todos.map((todo) => {
if (id === todo.id) {
todo = {
...todo,
complete: !todo.complete,
};
}
return todo;
}));
https://codesandbox.io/s/jovial-yalow-yd0jz
If asynchronous events are happening, the value in the scope of the executed event handler might be out of date.
When updating lists of values, use the updating method which receives the previous state, for example
setAlerts(previousAlerts => {
const newAlerts = (build new alerts from prev alerts);
return newAlerts;
});
instead of directly using the alerts you got from useState.
In the PageContainer.js, modify this function
const removeAlert = (id) => {
setAlerts(alerts.filter((alert) => alert.id !== id));
};
to this
const removeAlert = (id) => {
setAlerts(prev => prev.filter((alert) => alert.id !== id));
};
This will also fix the issue when unchecking completed todos at high speed

React usestate not updating on first Click Or on First time

Please, See this - https://codesandbox.io/s/morning-grass-z8qrq
https://codesandbox.io/s/blue-flower-wl92u
** the second click, third, fourth, fifth click - menuOpen is true, then again click false - behaves as expected**
let [menuOpen, setMenuOpen] = useState(false);
<div
onClick={() => {
// setMenuOpen(true);
setMenuOpen(!menuOpen); // I's not updated in the First time.
console.log(menuOpen); // First time: false // not updating
>
.......// some code
</div>
Please give me, some answers. I have been trying to solve this problem for Two days. I just can't solve it.
Try this:
export default function App() {
const [menuOpen, setMenuOpen] = useState(false);
return (
<>
<button onClick={() => setMenuOpen(!menuOpen)}>Click</button>
Is menu Open: { menuOpen ? "True": "False"}
</>
);
}
Example demo can be found here.
useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.
Give this a try
setMenuOpen(prevMenuOpenState => !prevMenuOpenState);
or
<div
onClick={() => setMenuOpen(!menuOpen)}
>
I had even this problem in my code. My scenario is as follows:
Its hotel detail page. There is horizontal tab menu of room types. If a hotel has more than 3 types of room, then there is show room button. I am using React Functional components in through the code. hotel detail basic page and room section page are different components created. values are passed to room section components through props.
My problem: When I click to room type further 3rd type, then show room value in function (setSelectedTab()) room component doesn't set at an instant. And hence as function moves further, it doesn't set document.getElementById(id) since show room had not been set. As function (setSelectedTab()) completes in first click it sets the show room to true, but selected tab doesn't set. I had to click 2nd time to set the tab.
solution:
After a long try and error, I settle down to the following:
I declare the function as async and made await the setshowRoom() value.
This solved my complete problem.
async function setSelectedTab(e, data) {
firstScroll += 1;
data >= 2 && await setMenuOpen(true);
if (data >= 0) {
.................
const id = e.href;
const anchor = document.getElementById(id);
..............
..............
}
}
and in room component: showRoom, setshowRoom in useState and calling the setSelectedTab() using props. This solves problem of single click
Drawback: I found delay of 1 second to set this tab.
If anyone have better solution than this without making async await, then please post here.
Thanks.
The Answer is just refactoring the code into class Component without using hooks useState. Using state and setState to update. The Problem will solve.
But If I use useState hooks the problem remains the same Whatever I do with the code.

Rendering React objects dynamically

My question is just about idea and creativity of you.
I have react component that is getting information from SQL database:
const [offers,setOffers] = useState([])
useEffect(()=>{
axios.get(`http://localhost:8085/incoming`)
.then(res=>{
setOffers(res.data.recordset)
})
.catch(error=>console.log(error))},[])
just when page is loaded.
In JSX I put one function that is filling my table:
<tbody className="table-hover">
{OfferItem(offers)}
</tbody>
The function is:
const OfferItem = (array)=>{
if(array!==undefined){
return array.map((item,index)=>{
return <IncomingOffer singleitem={item} index={index+1} key={item.Number}/>
})
}}
So far so good but I want to have input field that is providing dynamic search and re-rendering. So I put:
<label>Относно:</label><input onChange={searchAbout} />
And created my function:
const searchAbout = (e)=>{
e.preventDefault(e)
const string = e.target.value.toUpperCase()
const res = offers.filter(el=>Object.values(el).some(val=>val.toUpperCase().includes(string)))
setOffers(res)
}
In the way it is wrote it is working when typing in input field but as you see it is completely filtering the array and I am loosing all other items in it. So I was wondering for a way that I am filtering and re-rendering items but for example when I use backspace or remove the whole search criteria to see again my whole array information. I must admit I know how my code is working and what is expected but I do not know how to do it. Any ideas?

React good practice from parent state to children props

So i've been reading a lot lately on react state and props.
My app wasn't that big, but now i'm facing a problem that seems to be commun for a lot of people, and i'm trying to find the best way to implement this.
My app is simple. A SearchBar on top, that display a list of contact. My search bar is a component and is updating a react-redux store with the results of the searchBar value (calling a backend with axios). Till here everything works great.
When the results array is populate (in redux store), my container rerender the results array. Like this:
class Suggestions extends Component {
render() {
console.log('before map: ', this.props.contacts);
const {
contacts,
...rest
} = this.props;
const options = contacts.map((contact, index) => (
<Contact
key={contact.id}
renderToaster={renderToasterFunction}
contact={contact}
/>
));
return <div>{options}</div>;
}
}
const mapStateToProps = (state, props) => ({
contacts: state.contact.results,
});
export default connect(mapStateToProps)(Suggestions);
The problem happen in my Contact component, My list is a lirs of sometimes 10 contacts that are display on the same page. So my problem is that each Contact component need to have it's own state (to add or edit info exemple: if you need to add a new phone number).
//contact component
state = {
contactState: ???
}
...
render(){
//exemple for simplicity
return <div>{this.state.contactState.name}</div>
}
I've founded on react website that it's not a good idea to copy props from parent in state of child. And in my case i've seen it, because if i do this
...
state = {
contactState: this.props.contact <--info from parent
}
first search is ok, but second search with an other letter, results list is not updated and i still see some results of first search.
so i've tried to change my contact component to this:
//contact component
state = {
contactState: ???
}
...
render(){
//exemple for simplicity
return <input value={this.props.contact.name} onChange={this.handleChange}/>
}
And this is working great in term of visual update, all my contact are update even if i do 3-4 searches. But my problem is that, now when i want to edit the name i need to store all my contactState somewhere before saving this and second problem, because my component display {this.props.contact.name} when i edit this, the user can't see the new value, because i can't edit props.
So is there a way to render state from props in a child everytime the parent state change. Or is there a way to 1) save the state when the user edit a contact and 2) display the new value he has written ?
What is the best way when dealing with .map() to have one state foreach children that can be re-renderer when the parent state change and rendering all children with their new state.
Thank you for your help.
Don't hesitate if you need more precisions.
I'm not sure to understand everything but if I get what you want to do:
A simple solution could be to dispatch an action on the onChange
The reducer which catch the action will update your redux store
The props will change and the View too.
But that's will make you dispatch A LOT of actions...
Other option :
Use a state in every Contact-Component which duplicates props
state = {...this.props.contact}
Modify the state on the change handler and use it as value too.
Save and dispatch the "final name" to update redux store and call the api at the same moment to update in on your server
Let me know if that's clear enough

Categories

Resources