How do i pass data values to modals using react hooks? - javascript

I am working on using modals to accept form inputs on a react project
here is the plan component
plan/index.js
import React, { useState } from "react";
import Pay from '../Pay';
const Plan = () => {
const [payModal, setPayModal] = useState(false);
const [planMode, setPlanMode] = useState(true);
return (
<main class="main">
{payModal && <Pay setOpenPayModal={setPayModal} />}
<div class="plan">
<div>
<a class="plans" onClick={() => {setPayModal(true);}}>plan A</a>
<div class="plan">
<span class="plan">{!planMode ? "$19.99" : "$9.99"}</span>
<span class="plan">{!planMode ? "month" : "year"}</span>
</div>
</div>
<div>
<a class="plans" onClick={() => {setPayModal(true);}}>plan B</a>
<div class="plan">
<span class="plan">{!planMode ? "$29.99" : "$19.99"}</span>
<span class="plan">{!planMode ? "month" : "year"}</span>
</div>
</div>
</div>
</main>
);
};
export default Plan;
as you can see on the line {payModal && <Pay setOpenPayModal={setPayModal} />} where i call the pay modal component from the plan component and it opens up the modal
here is the pay component which is the modal component
pay/index.js
import React, { useState } from "react";
function Pay({ setOpenPayModal }) {
const [billingDetails, setBillingDetails] = useState({
price: "",
: "",
});
return (
<div class="modal">
<div class="modal">
<div class="close">
<button
onClick={() => {
setOpenPayModal(false);
}}
>
</button>
</div>
<div class="modal">
<form class="form" onSubmit={handleSubmit}>
<fieldset class="form">
<Field
label="Price"
id="price"
type="text"
value={billingDetails.price}
onChange={(e) => {
setBillingDetails({ ...billingDetails, price: e.target.value });
}}
/>
<Field
label="Frequency"
id="frequency"
type="text"
value={billingDetails.frequency}
onChange={(e) => {
setBillingDetails({ ...billingDetails, frequency: e.target.value });
}}
/>
</fieldset>
<button class="pay" onClick={handleSubmitPay}>
Pay
</button>
</form>
</div>
</div>
</div>
);
}
export default Pay;
The issue is I want to be able to pass the values price and frequency from the plan component to the pay modal component
for example for plan A is price="$19.99" and frequency="year", so based on the button clicked on the plan component page, those values get passed to the pay modal component in a dynamic way
how do I achieve this using react hooks?

You can use contexts to pass, but in this case I don't think it's the best option. What I really recommend is passing the state variable through the props.
{payModal && <Pay setOpenPayModal={setPayModal} price={price} frequency={frequency} />}
I usually use the Context (useContext) when I need values and various components, for example:
I need to save the user id that is logged in to various components, and instead of getting it from the server every time I need it, I keep it saved in my context that I created, so I can make the call only once.
Documentation-> https://pt-br.reactjs.org/docs/context.html

Related

How can I use the hook's value from one jsx to other

I am making a cart and when I click Add to cart then the number of times increases this is done using hooks and is in the following Pricetag.jsx
import React from 'react'
import './Body.css'
import { useState } from 'react'
// import './Cart.js'
export default function Pricetag(props) {
const [count, setCartCount] = useState(0);
return (
<div>
<div className="card1">
<div className="image">
<img src={props.images} alt="" className='card-image' />
</div>
<div className="content">
<div className="name">
{props.name}
</div>
</div>
<div className="button">
<button className='btn no1' id='cartbutton' onClick={() => setCartCount(count + 1)} >
Add to cart
</button>
<br></br>
</div>
</div>
</div>
)
}
Now I want to use the value of count in other jsx,
import React from 'react'
import './Body.css'
import image2 from './assets/cake9.jpeg'
import image9 from './assets/cake16.jpeg'
import Pricetag from './Pricetag'
export default function Body(props) {
return (
<>
<div className="headingbody">
<div></div>
{props.title}
</div>
<div className="cart">
<div className="number34"> ** here I want to show my count **</div>
<i class="fa-solid fa-cart-shopping"></i>
</div>
<hr className='latestline' />
<div className='container1'>
<Pricetag images={image10} name="Swimming cake" bold="Rs 345" cut="Rs 634" />
<Pricetag images={image11} name="Rossy cake" bold="Rs 345" cut="Rs 634" />
</div>
</>
)
}
Can you tell me how can I use the value of count from the first to the second?
There are a few ways you can use:
state management: redux, zustand,...
using React Context
you can pass the value through props but it will cause 'hell props'
You have to pass the count state to the other JSX file (component). There are some ways:
Import the JSX file and call the component inside Pricetag.jsx, then pass count as a prop.
If you are unable to use the component inside Pricetag.jsx, then Use state management solutions like Context API, Redux, MobX etc.
brother, you can find the description and idea from the below document of useContext API calling and its functionaloty
https://www.geeksforgeeks.org/reactjs-usecontext-hook/
https://reactjs.org/docs/hooks-reference.html#usecontext

How to make React search component

I am doing my first Ecommerce MERN stack project but i donot know how to make search component that will take the search input and return array of matching products
If you want to make it fast you can get a graphic library like Material UI : https://mui.com/
Like this you can use pre-created components like this one that have autocomplete: https://mui.com/components/autocomplete/#search-input
You don't tell a lot of details about your case but to use it, you have to configure a route that returns you a list of the researched input everytime there is a change in this said input (configure the onChange function of the input section to request the list everytime there is a change).
To add a search:
Render your search bar component in the app
Add your HTML elements
Add a list of posts
Filter the list based on your search query
Adding immediate search or “search as you type”
Adding SPA navigation with React Router
“Search as you type”, SPA navigation and accessibility concerns
Testing your component with React Testing Library
Conclusion
If you want to know more precisely, you can view and understand the related material at the following URL.
https://www.emgoto.com/react-search-bar/
Best regards.
Using bootstrap:
import React, { useState } from "react";
import { useRouter } from "next/router";
const Search = () => {
const [location, setLocation] = useState("");
const [guests, setGuests] = useState("");
const [category, setCategory] = useState("");
const router = useRouter();
const submitHandler = (e) => {
e.preventDefault();
if (location.trim()) {
router.push(
// this will push it to home page with query params
// in home pag, based on these query params, you should be fetching data
`/?location=${location}&guests=${guests}&category=${category}`
);
} else {
router.push("/");
}
};
return (
// using bootstrap classes
<div className="container container-fluid">
<div className="row wrapper">
<div className="col-10 col-lg-5">
<form className="shadow-lg" onSubmit={submitHandler}>
<h2 className="mb-3">Search Rooms</h2>
<div className="form-group">
<label htmlFor="location_field">Location</label>
<input
type="text"
className="form-control"
id="location_field"
placeholder="new york"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
</div>
<div className="form-group">
<label htmlFor="guest_field">No. of Guests</label>
{/* The <select> element is used to create a drop-down list. */}
<select
className="form-control"
id="guest_field"
value={guests}
onChange={(e) => setGuests(e.target.value)}
>
{/* upto 6 guests */}
{[1, 2, 3, 4, 5, 6].map((num) => (
// The <option> tags inside the <select> element define the available options in the drop-down list.
<option key={num} value={num}>
{num}
</option>
))}
</select>
</div>
<div className="form-group">
<label htmlFor="room_type_field">Room Type</label>
<select
className="form-control"
id="room_type_field"
value={category}
onChange={(e) => setCategory(e.target.value)}
>
{["King", "Single", "Twins"].map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
</div>
<button type="submit" className="btn btn-block py-2">
Search
</button>
</form>
</div>
</div>
</div>
);
};
export default Search;

I am new to react. I want to render a child component using a single state using an onClick event in react JS

on Click of button the state should be able to render component using statename.map.. Thankyou
<div className="container mt-5">
<div className="row">
<div className="card pt-3">
<div className="col-lg-12">
<h4>Promotional Rates</h4>
<p>
Create promotional rate(s)
</p>
<button className="btn btn-primary my-3" onClick={???}>
Add New Promotional Rates
</button>
<<<<<<<render child component here using .map>>>>>>>>>
</div>
</div>
</div>
</div>
creat a state and u can use whatever method in the js code bellow
import React,{useState} from "react"
const ParentComponent = () =>{
const [ShowChild,setShowChild]=useState(false)
return(
<div>
//methode 1
{ShowChild && ChildComponent}
// end methode 1
//methode 2
{ShowChild? <ChildComponent /> : ''}
//end methode 2
<button onClick={()=>setShowChild(!ShowChild)}>show child Button </button>
</div>
)}
const ChildComponent = () => {
return(
<h1>I m a child</h1>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

How to properly search in a list in ReactJS

I am trying to set a simple search operation in a user interface as shown below:
I have a total of 70 react-strap cards and each card contain a vessel with name, type and an image. I would like to search the name of the vessel and have the card related to that vessel to pop-up. All my images are currently contained inside the external database Contentful. Below the fields of interests:
The problem is that I don't know how to write a search function that locate a specific value of a list.
Below the code:
SideBar.js
import React from 'react';
import Client from '../Contentful';
import SearchVessel from '../components/SearchVessel';
class Sidebar extends React.Component {
state = {
ships: [],
};
async componentDidMount() {
let response = await Client.getEntries({
content_type: 'cards'
});
const ships = response.items.map((item) => {
const {
name,
slug,
type
} = item.fields;
return {
name,
slug,
type
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
if (!this.props.activeShip) {
return this.state.ships;
}
let targetShip = this.state.ships.filter(
(ship) => this.props.activeShip.name === ship.name
);
let otherShipsArray = this.state.ships.filter((ship) => this.props.activeShip.name !== ship.name);
return targetShip.concat(otherShipsArray);
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<SearchVessel />
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<div className="row">
<img
className="image-sizing-primary"
src={ship.companylogo.fields.file.url}
alt="shipImage"
/>
</div>
<div>
<img
className="image-sizing-secondary"
src={ship.images.fields.file.url}
alt="shipImage"
/>
</div>
<CardTitle>
<h3 className="thick">{ship.name}</h3>
</CardTitle>
<CardSubtitle>{ship.type}</CardSubtitle>
<CardText>
<br />
<h6>Project Details</h6>
<p>For a description of the project view the specification included</p>
</CardText>
<Row style={{ marginTop: '20px' }}>
<div className="buttoncontainer">
<div className="btn btn-cards">
<a
className="buttonLink"
download
href={ship.projectnotes.fields.file.url}
>
Project Notes
</a>
</div>
<div className="btn btn-cards">
<a className="buttonLink" href={ship.abstract.fields.file.url}>
Abstract
</a>
</div>
</div>
</Row>
</CardBody>
</Card>
);
})}
</pre>
</div>
);
}
}
export default Sidebar;
VesselSearch.js
import React, { Component } from 'react';
export default class SearchVessel extends Component {
render() {
const { value, handleSubmit, handleChange } = this.props;
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-10 mx-auto col-md-8 mt-5 text-center">
<h4 className="text-slanted text-capitalize">Search for Vessel</h4>
<form className="mt-4" onSubmit={handleSubmit}>
<label htmlFor="search" className="text-capitalize">
type vessel separated by comma
</label>
<div className="input-group">
<input
type="text"
name="search"
placeholder="Type name of vessel here"
className="form-control"
value={value}
onChange={handleChange}
/>
<div className="input-group-append">
<button type="submit" className="input-group-text bg-primary text-white">
<i className="fas fa-search" />
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</React.Fragment>
);
}
}
What I have done so far:
1) I tried different combination with the filter function and I think I am close. The problem is that when I operate the search nothing happens and in order to find the card of the vessel I want, I have to scroll down until I find it.
I am running out of ideas and if you see something I didn't catch point me in the right direction for solving this issue.
You're close! I would add a field to your state called 'searchText' and then create a method to filter based on that searchText state item.
getFilteredShips = () => this.state.ships.filter(s => s.name.includes(this.state.searchText)
Then just map over those values to render the cards that match the search text. The cards will update each time the searchText value updates.
this.getFilteredShips().map(ship => ..........
React is famous for re-usable component. You will have all the data of these vessels in an array. You will loop through the array and render the items with card component.And when you search for the specific card you want that vessel to pop out on top.
There are two ways to do it:
You have to run through the array, find the index of that vessel and do whatever it takes to manipulate your array and to make that item at top and re-render your list.
Alternatively render one more component on top of your vessel list as user clicks the search button. You just have to find the item index and render it. This way you don't have to deal with array manipulation. It doesn't matter if you have 80 or 1000 cards.
Please checkout official documentation for array methods, for array slicing and splice.
Hope this is what you are looking for. If you need further help, comment please.

Issues passing data up React tree to change DOM

** This may be a simple answer, I'm new to React, thank you for any help ! **
Back story
I have a modal(bootstrap4) hidden inside the main app with a form inside that, when it rendered, the form is filled out based on the information from the selected recipe (more on that later.)
The recipes are stored locally and with this.state.currentRecipe I know which recipe is being selected (it is used as the index and is set to 0 by default.)
So, using this.state.currentRecipe as the index the first render naturally puts in the first recipe's information.
I attempted to solve this by making a function and passing it down the child components. The recipe-card has all the information and the edit button inside of it. So when the recipe-cards are all rendered by .map() I pass in their index and the function that was passed down in order to change the state of this.state.currentRecipe and re-render the DOM with the form having the new information.
What's wrong
Everything loads however, when I click the edit button the modal pops up with the first recipe always. It will even change this.state.currentRecipe but the DOM doesn't re-render with the proper recipe's information.
How do I get the form's information to update based on which recipe-card I'm in when I click the 'Edit' button?(there is a button in each card).
(and even if it did, would it just hide the modal again?)
Here is the link to the component folder of the repo https://github.com/JeremyWeisener/React-Recipe-box/tree/master/src/components
in case the code below isn't enough information
Here is the inside of the 4 main files I believe matter (cleaned up a bit and put here to make life easier)
app.js
import React, { Component } from 'react';
import RecipeCard from './recipe-card';
import RecipeBook from './recipe-book';
import AddRecipe from './add-recipe';
import RecipeEditer from './edit-recipe';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
currentRecipe: 0,
recipes: JSON.parse(localStorage.getItem('cookBook')),
updateKey: 0,
counter: 0
}
}
changeRecipe = (arg) => {
this.setState({currentRecipe:arg});
}
render() {
return (
<div>
<div>
<RecipeBook changeRecipe={this.changeRecipe.bind(this)} recipes={this.state.recipes} />
</div>
<div id="popUps">
<AddRecipe />
<RecipeEditer index={this.state.currentRecipe} forglory={this.state} />
</div>
<div id="editPopup">
</div>
</div>
);
}
}
recipe-book.js
import React from 'react';
import RecipeCard from './recipe-card';
const RecipeBook = (props) => {
var changeRecipe = props.changeRecipe;
console.log(props);
const DisplayRecipes = props.recipes.map((recipe, index) => {
return <RecipeCard index={index} key={index+1} recipe={recipe} changeRecipe={changeRecipe.bind(this)} />
})
return (
<div id="accordion" role="tablist" aria-multiselectable="true">
{DisplayRecipes}
<div>
<button className="btn btn-primary" type="button" data-toggle="modal" data-target="#addRecipe"> Add Recipe </button>
</div>
</div>
);
}
export default RecipeBook;
recipe-card.js
import React from 'react';
import Ingredients from './recipe-ingredients';
import Steps from './recipe-steps';
import RecipeEditer from './edit-recipe';
const RecipeCard = (props) => {
const changeRecipe = props.changeRecipe;
return (
<div>
{/*Card Start*/}
<div className="recipe card">
{/*Header*/}
<div className="card-header" role="tab" id={`heading${props.index}`}>
<h5 className="mb-0">
<a data-toggle="collapse" data-parent="#accordion" href={`#collapse${props.index}`} aria-expanded="true" aria-controls={`collapse${props.index}`}>
{props.recipe.title}
</a>
</h5>
</div>
{/*End Header*/}
{/*Collapse Div*/}
<div id={`collapse${props.index}`} className="collapse" role="tabpanel" aria-labelledby={`heading${props.index}`}>
{/*Card IMG*/}
<img className="card-img-top" src="./img/Fried Chik'n-edit1.jpg" />
{/*Card Block*/}
<div className="card-block">
<p className="card-text">
</p>
{/* Ingredients */}
<h3>Ingredients</h3>
<Ingredients parts={props.recipe.ingredients} />
{/* Steps */}
<h3>Steps</h3>
<Steps levels={props.recipe.steps} />
Print Recipe
{/*Edit Button is here*/}
<button onClick={() => {changeRecipe(props.index)}} className="btn btn-success" type="button" data-toggle="modal" data-target="#editRecipe"> Edit Recipe </button>
{/*Edit Button is here*/}
Delete Recipe
</div>
{/*End Card Block*/}
</div>
{/*End Collapsable*/}
</div>
{/*End Card*/}
</div>
);
}
export default RecipeCard;
edit-recipe.js
import React from 'react';
const RecipeEditer = (props) => {
var index = props.index;
var cookBook = JSON.parse(localStorage.getItem("cookBook"));
var editMe = cookBook[props.forglory.currentRecipe];
const UpdateRecipe = () => {
var formData = $('#recipeEditer').serializeArray();
var newRecipe = {};
newRecipe.title = formData[0]['value'];
newRecipe.image = formData[1]['value'];
newRecipe.ingredients = formData[2]['value'].split(',');
newRecipe.steps = formData[3]['value'].split(',');
cookBook[index] = newRecipe;
localStorage.setItem("cookBook", JSON.stringify(cookBook));
}
return (
<div className="modal fade" id="editRecipe" tabIndex="-1" role="dialog" aria-labelledby="editRecipeLabel" aria-hidden="false">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
{/* Title */}
<h5 className="modal-title" id="exampleModalLabel">
Edit Recipe
</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="false">×</span>
</button>
</div>
<div className="modal-body">
<form id="recipeEditer" name="editRecipe">
<label htmlFor="name"><h4>Name</h4></label>
<input id="name" className="form-control" name="title" type="text" defaultValue={editMe.title} />
<label htmlFor="image"><h4>Image</h4></label>
<input id="image" className="form-control" name="image" type="text" defaultValue={editMe.image} />
<label htmlFor="ingredients"><h4>Ingredients</h4></label>
<textarea id="ingredients" className="form-control" name="ingredients" rows="4" cols="48" defaultValue={editMe.ingredients}></textarea>
<label htmlFor="steps"><h4>Steps</h4></label><br/>
<textarea id="steps" className="form-control" name="steps" cols="48" rows="4" defaultValue={editMe.steps} ></textarea>
</form>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-dismiss="modal">Close</button>
{/*Submit Button*/}
<button onClick={UpdateRecipe} type="button" className="btn btn-success" data-dismiss="modal">Change Recipe</button>
{/*Submit Button*/}
</div>
</div>
</div>
</div>
);
}
export default RecipeEditer;
thank you very much if you even glanced, if there is any more information that can help please don't hesitate to ask !
You are binding changeRecipe to this in recipe-book.js, thus setting its context to RecipeBook.
Try changing
<RecipeCard index={index} key={index+1} recipe={recipe} changeRecipe={changeRecipe.bind(this)} />
to
<RecipeCard index={index} key={index+1} recipe={recipe} changeRecipe={changeRecipe} />
You may not even have to use bind in app.js, since changeRecipe is defined as an arrow function.

Categories

Resources