I'm trying to create a basic react app which contains 4 Reactstrap Card Items and now I want this functionality where when I click at one of the cards, the clicked card gets copied all the way at the end of the page and we display additional information related to the card.
Here is one of the component code-
import React,{useState} from "react";
import 'bootstrap/dist/css/bootstrap.min.css';
import {Card, CardImg, CardImgOverlay, CardText, CardBody,
CardTitle} from "reactstrap";
function MenuComponent (props){
return (
<div className="container">
<div className="row">
{props.dishes.map((dish)=>{
return (
<div className="col-12 col-md-5 m-1">
<Card key={dish.id} >
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
}
)
}
</div>
</div>
);
}
export default MenuComponent;
Here is the Dishes array of objects having the details about the dish-
Dishes=[
{
id: 0,
name:'Uthappizza',
image: 'asset/images/uthappizza.png',
category: 'mains',
label:'Hot',
price:'4.99',
description:'A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.' },
{
id: 1,
name:'Zucchipakoda',
image: 'asset/images/zucchipakoda.png',
category: 'appetizer',
label:'',
price:'1.99',
description:'Deep fried Zucchini coated with mildly spiced Chickpea flour batter accompanied with a sweet-tangy tamarind sauce' },
{
id: 2,
name:'Vadonut',
image: 'asset/images/vadonut.png',
category: 'appetizer',
label:'New',
price:'1.99',
description:'A quintessential ConFusion experience, is it a vada or is it a donut?' },
{
id: 3,
name:'ElaiCheese Cake',
image: 'asset/images/elaicheesecake.png',
category: 'dessert',
label:'',
price:'2.99',
description:'A delectable, semi-sweet New York Style Cheese Cake, with Graham cracker crust and spiced with Indian cardamoms' }
];
If you need to copy the content of a dish, it's possible to use this lib https://www.npmjs.com/package/copy-to-clipboard in this way.
import React, { useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import {
Card,
CardImg,
CardImgOverlay,
CardText,
CardBody,
CardTitle,
} from "reactstrap";
import copy from "copy-to-clipboard";
function MenuComponent(props) {
const copyHandler = (dish) => {
copy(dish.name);
};
return (
<div className="container">
<div className="row">
{props.dishes.map((dish) => {
return (
<div className="col-12 col-md-5 m-1">
<Card key={dish.id} onClick={() => copyHandler(dish)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
})}
</div>
</div>
);
}
export default MenuComponent;
But if you need to get a new copy of the element, the best choice would be to receive the setState function for props and execute in a handler like in the example above or apply the dishes in the component's state.
Related
The goal is to display a series of recipes. The user first gets a general overview of the available recipes containing the name of the recipe, a picture, and some basic information (time to cook, etc). When the user clicks a button (show full recipe), the full recipe should be shown. When the user clicks a new button (hide full recipe) the full recipe is hidden again and the user only sees a general overview of the recipes.
For now, I have created an array of (two) recipes. By using a map() I return the different recipes. However, when the show or hide full recipe button is clicked, all the recipes are shown. How can I make sure that when the user clicks 'show full recipe', he/she only gets to see the specific recipe?
import React, { useState } from 'react';
var recipes = [{
_id: 1,
title: "Spaghetti",
type: "Dinner or Lunch",
category: "vegan",
image: "http://via.placeholder.com/350x250",
cookingTime: 35,
ingredients: [[1, "onion"], [3, "tomato"], [1, "aubergine"], [1, "beans"], [1, "tomatoesauce"], [1, "tomatoconcentrate"], [1, "pepper"], [1, "salt"], [1, "pasta"]],
cookingSteps: [["Boil a pot full of watter. Once the watter is boiling, add the pasta. The cooking time depends on the pasta."], ["Cut the onion and the garlic. Add them to a poth with olive oil. Cook for 2 to 3 minutes"], ["Cut the other vegetables. After the onion and the garlic are marrinated, add the different vegtables to the poth. Let them cook with the lid on for about 10 to 15 minutes or untill the vegetables are ready."], ["Once the vegetables are ready, add the tomato sauce and the tomato concentrate. Add the beans. Let this cook for another five minutes"], ["Remove the lid from the pot. Add pepper and salt and other additional spcices, like italian spcies or special peppers"]]
},
{
_id: 2,
title: "Eggs",
type: "Breakfast",
category: "vegan",
image: "http://via.placeholder.com/350x250",
cookingTime: 10,
ingredients: [[4, "egg"], [1, "tomato"], [1, "pepper"], [1, "salt"]],
cookingSteps: [["cut the tomato. Heat olive oil in a pan, add the tomato and bake it till the outer peal of the tomato gets soft. If you like pepper, it is adviced to first bake the pepper a bit in the pan"], ["Meanwhile, scrambel the eggs. Once the tomatoes are ready (see step 1), add the eggs"]]
}
];
//TODO: make sure only one specific recipe shows when clicked
function DisplayRecipes(){
//declare useState and onClick for button to show full recipe
const[isNotDisplayed, isDisplayed] = React.useState(false)
const onClickShow = () => {isDisplayed(true)};
const onClickHIde = () => isDisplayed(false);
//return statement to render recipe
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Our vegan recipes...</h1>
<div className="row">
{
recipes.map((recipe)=>{
return(
<div key={recipe._id} className="col-md-3">
<div className="card bwm-card">
<div className="card-title">
<h2>{recipe.title}</h2>
</div>
<img className="card-img-top" src={recipe.image} alt={recipe.title} />
<div className="card-subtitle">
<h3><b>Type: {recipe.type} </b></h3>
<h3><b>Category: {recipe.category}</b></h3>
<h3><b>Cooking time: {recipe.cookingTime} minutes</b></h3>
</div>
<div>
{ isNotDisplayed ?
<div className="card-body">
<div className="card-body-ingredient">
{
recipe.ingredients.map((ingredient, i) =>{
return(
<table>
<tr>
<th>Quantity</th>
<th>Ingredient</th>
</tr>
<tr>
<th>{ingredient[0]}</th>
<th>{ingredient[1]}</th>
</tr>
</table>
)
})
}
</div>
<div className="card-body-cookingsteps">
{
recipe.cookingSteps.map((cookingstep, i) =>{
return(
<p>{cookingstep}</p>
)
})
}
</div>
<div>
<button type="submit" value="Hide full recipe" onClick= {onClickHIde}>Hide full recipe</button>
</div>
</div>
:
<button type="submit" value="Show full recipe" onClick= {onClickShow}>Show full recipe</button>
}
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
export default DisplayRecipes;
Thank you in advance!
You need a separate piece of state for each recipe. Currently all the recipes share the same state, so when one is open, they're all open.
The best way to separate out the state is to make each recipe its own component with its own state.
import React, {useState} from 'react';
const recipes = [
{
_id: 1,
title: 'Spaghetti',
type: 'Dinner or Lunch',
category: 'vegan',
image: 'http://via.placeholder.com/350x250',
cookingTime: 35,
ingredients: [
[1, 'onion'],
[3, 'tomato'],
[1, 'aubergine'],
[1, 'beans'],
[1, 'tomatoesauce'],
[1, 'tomatoconcentrate'],
[1, 'pepper'],
[1, 'salt'],
[1, 'pasta'],
],
cookingSteps: [
[
'Boil a pot full of watter. Once the watter is boiling, add the pasta. The cooking time depends on the pasta.',
],
[
'Cut the onion and the garlic. Add them to a poth with olive oil. Cook for 2 to 3 minutes',
],
[
'Cut the other vegetables. After the onion and the garlic are marrinated, add the different vegtables to the poth. Let them cook with the lid on for about 10 to 15 minutes or untill the vegetables are ready.',
],
[
'Once the vegetables are ready, add the tomato sauce and the tomato concentrate. Add the beans. Let this cook for another five minutes',
],
[
'Remove the lid from the pot. Add pepper and salt and other additional spcices, like italian spcies or special peppers',
],
],
},
{
_id: 2,
title: 'Eggs',
type: 'Breakfast',
category: 'vegan',
image: 'http://via.placeholder.com/350x250',
cookingTime: 10,
ingredients: [
[4, 'egg'],
[1, 'tomato'],
[1, 'pepper'],
[1, 'salt'],
],
cookingSteps: [
[
'cut the tomato. Heat olive oil in a pan, add the tomato and bake it till the outer peal of the tomato gets soft. If you like pepper, it is adviced to first bake the pepper a bit in the pan',
],
[
'Meanwhile, scrambel the eggs. Once the tomatoes are ready (see step 1), add the eggs',
],
],
},
];
const Recipe = ({recipe}) => {
const [isOpen, setIsOpen] = React.useState(false);
return (
<div className="col-md-3">
<div className="card bwm-card">
<div className="card-title">
<h2>{recipe.title}</h2>
</div>
<img className="card-img-top" src={recipe.image} alt={recipe.title} />
<div className="card-subtitle">
<h3>
<b>Type: {recipe.type} </b>
</h3>
<h3>
<b>Category: {recipe.category}</b>
</h3>
<h3>
<b>Cooking time: {recipe.cookingTime} minutes</b>
</h3>
</div>
<div>
{isOpen ? (
<div className="card-body">
<div className="card-body-ingredient">
{recipe.ingredients.map((ingredient, i) => {
return (
<table>
<tr>
<th>Quantity</th>
<th>Ingredient</th>
</tr>
<tr>
<th>{ingredient[0]}</th>
<th>{ingredient[1]}</th>
</tr>
</table>
);
})}
</div>
<div className="card-body-cookingsteps">
{recipe.cookingSteps.map((cookingstep, i) => {
return <p>{cookingstep}</p>;
})}
</div>
<div>
<button
type="submit"
value="Hide full recipe"
onClick={() => setIsOpen(false)}>
Hide full recipe
</button>
</div>
</div>
) : (
<button
type="submit"
value="Show full recipe"
onClick={() => setIsOpen(true)}>
Show full recipe
</button>
)}
</div>
</div>
</div>
);
};
function DisplayRecipes() {
return (
<div className="card-list">
<div className="container">
<h1 className="page-title">Our vegan recipes...</h1>
<div className="row">
{recipes.map((recipe) => (
<Recipe key={recipe._id} recipe={recipe} />
))}
</div>
</div>
</div>
);
}
export default DisplayRecipes;
You can consider using refs here:
Pass the ref to your onClickShow and show the div with that particular ref.
You can also use CSS, in this case, get the div using the ref and mark display of that div as none and vice-versa.
Im new to react.js and have been facing this issue.Im working on this app dishes where the user clicks one dish and then it is rendered in form a card.The value of dish is passed as a props from menucomponent to DishDetail but in doing so the dish object is always receiving null value for which there is nothing on the screen . please help me with it.im attaching both MenuComponents.js and DishDetail.js
the MenuComponent.js is:
import React, { Component } from 'react';
// import { Media } from 'reactstrap';
import { Card, CardImg, CardImgOverlay, CardText, CardBody,CardTitle } from 'reactstrap';
import DishDetail from './DishdetailComponent';
class Menu extends Component {
constructor(props) {
super(props);
this.state = {
selectedDish: null
};
}
onDishSelect(dish) {
this.setState({ selectedDish: dish});
}
render() {
const menu = this.props.dishes.map((dish) => {
return(
<div key={dish.id} className="col-12 col-md-5 m-1">
{/* <Media tag="li">
<Media left middle>
<Media object src={dish.image} alt={dish.name} />
</Media>
<Media body className="ml-5">
<Media heading>{dish.name}</Media>
<p>{dish.description}</p>
</Media>
</Media> */}
<Card key={dish.id} onClick={() => this.onDishSelect(dish)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return(
<div className="container">
<div className="row">
{/* <Media list>
{menu}
</Media> */}
{menu}
</div>
<DishDetail dish={this.state.selectedDish} />
</div>
);
}
}
export default Menu;
the DishDetail.js is:
import React, { Component } from 'react';
import { Card, CardImg, CardImgOverlay, CardText, CardBody,CardTitle } from 'reactstrap';
class DishDetail extends Component{
constructor(props){
super(props);
}
renderDish(dish) {
if (dish != null)
return(
<Card>
<CardImg top src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
);
else
return(
<div></div>
);
}
render() {
const dish = this.props.selectedDish;
console.log(dish);
return(
<div className="row">
<div className="col-12 col-md-5 m-1">
{this.renderDish(this.props.selectedDish)}
</div>
<div className="col-12 col-md-5 m-1">
</div>
</div>
);
}
}
export default DishDetail;
You're passing a property named dish to your component but using selectedDish.
<DishDetail dish={this.state.selectedDish} />
const dish = this.props.selectedDish;
The prop passed to the DishDetail component is called dish:
// MenuComponent.js
<DishDetail dish={this.state.selectedDish} />
However DishDetail is expecting a prop with the name selectedDish:
// DishDetail.js
const dish = this.props.selectedDish;
{this.renderDish(this.props.selectedDish)}
Updating DishDetail to use this.props.dish will resolve your issue:
const dish = this.props.dish;
{this.renderDish(this.props.dish)}
I am new to using React Hooks with stateless components. I usually use stateful components when I have to use state. My present app requires the context API which could only be used in functional Components. I have rewritten most of the code I need to work but one brings an error "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."
The Component I am trying to convert to a functional one
class pizzas extends Component {
state ={
pizzas: [
{id:1, name: 'Chicken Curry', ingredients: 'Red onions, bell peppers, chicken, pineapple, mozzarella, tomato sauce, curry, chili peppers', price: '3100', image: chickenCurry },
{id:2, name: 'Pepperoni Fresh', ingredients: 'Pepperoni, mozzarella, green peppers, pizza sauce', price: '2700', image: pepperoniFresh },
{id:3, name: 'Chicken BBQ', ingredients: 'Chicken, red onions, corn, mozzarella, bbq sauce, tomato sauce', price: '2700', image: chickenBbq },
{id:4, name: 'Shawarma Pizza', ingredients: 'Mayonnaise & ketchup, spicy chicken, red onions, tomatoes, mozzarella', price: '3100', image: sharwarmaPizza },
{id:5, name: 'Chicken Suya', ingredients: 'Mayonnaise, spicy sauce, spicy chicken, bell peppers, red onions, suya sauce, tomato sauce, mozzarella, suya spice', price: '2700', image: chickenSuya },
{id:6, name: 'Pepperoni', ingredients: 'Pepperoni, mozzarella, tomato sauce', price: '2700', image: pepperoni },
{id:7, name: 'Beef Suya', ingredients: 'Mayonnaise, spicy sauce, spicy meatballs, bell peppers, red onions, mozzarella, suya sauce, tomato sauce, suya spice', price: '2700', image: beefSuya },
{id:8, name: 'Chicken Supreme', ingredients: 'Spicy sauce, chicken and spicy chicken, mushrooms, bell peppers, olives, red onions, mozzarella, tomato sauce', price: '3100', image: chickenSupreme },
{id:9, name: 'Sweet Chili Chicken', ingredients: 'Spicy sauce, chicken, chili pepper, mozzarella, sweet chili sauce, tomato sauce', price: '2700', image: chickenCurry },
{id:10, name: 'Spicy Mixed Pizza', ingredients: 'Spicy sauce, spicy meatballs, spicy chicken, chili pepper, corn, mozzarella, buffalo sauce, tomato sauce', price: '3100', image: spicyMixedPizza },
{id:11, name: 'Margherita', ingredients: 'Mozarella, tomato sauce', price: '2200', image: margherita },
{id:12, name: 'Super Meaty', ingredients: 'Chicken, pepperonni, sausages, mozzarella, tomato sauce', price: '3100', image: superMeaty },
{id:13, name: 'Cheesy Chicken', ingredients: 'Chicken, tomatoes, cheddar, mozzarella, cheese sauce', price: '2700', image: cheesyChicken },
{id:14, name: 'Cheeseburger Pizza', ingredients: 'Beef, tomatoes, red onions, cheddar, mozzarella, mayonnaise & ketchup, tomato sauce', price: '3100', image: cheeseBurger },
{id:15, name: 'Meaty Overload', ingredients: 'Spicy sauce, pepperonni, spicy meatballs, chicken, sausages, mozzarella, tomato sauce', price: '3400', image: meatyOverload },
{id:16, name: 'Meaty BBQ', ingredients: 'Beef, pepperonni, sausages, mozzarella, bbq sauce, tomato sauce', price: '3100', image: meatyBbq },
{id:17, name: 'Hawaiian', ingredients: 'Chicken, pineapple, mozzarella, sweet chili sauce, tomato sauce', price: '2700', image: hawaiian },
{id:18, name: 'Veggie Overload', ingredients: 'Mushrooms, bell peppers, corn, olives, red onions, tomatoes, mozzarella, tomato sauce', price: '3100', image: veggieOverload }
],
showModal: false,
selectedPizza: null,
orders: []
}
toggleModalHandler = (p)=>{
this.setState({showModal: !this.state.showModal, selectedPizza: p});
}
addToOrders = (productName, productIngredients, productPrice, productImage, p)=>{
this.setState(prevState=>({
orders: [...prevState.orders, productImage, productName, productIngredients, productPrice]
}))
}
render(){
const pizza = this.state.pizzas;
return (
<Aux>
{ this.state.showModal?
<Backdrop clicked={this.toggleModalHandler}/>: null}
{ this.state.showModal ?
<Modal
clicked={this.toggleModalHandler}
sendRequest={this.sendingRequestHandler}
ingredients={this.state.selectedPizza.ingredients}
price={this.state.selectedPizza.price}
image={this.state.selectedPizza.image}
name={this.state.selectedPizza.name}
key={this.state.pizzas.id}
addToOrders={this.addToOrders}/>: null}
<div className={styles.Pizza} id="pizza">
<h1>Pizza</h1>
<div className={styles.PizzaContainer}>
{pizza.map(p=>{
return <div>
<div className={styles.PizzaCard}>
<div className={styles.PizzaCardHeader}>
<img src={p.image} alt="pizza"/>
<h1>{p.name}</h1>
<p>{p.ingredients}</p>
</div>
<div className={styles.PizzaCardFooter}>
<h3>from ₦{p.price}</h3>
<button onClick={()=>this.toggleModalHandler(p)}>Select</button>
</div>
</div>
</div>
})}
</div>
</div>
</Aux>
)
}
}
export default pizzas;
What I have done so far
const Pizzas = () => {
const [showModal, setModal] = useState(false);
const [selectedPizza, setSelectedPizza] = useState(null)
const { pizzaproducts } = useContext(ProductsContext)
const toggleModalHandler = (p) => {
setModal(true);
setSelectedPizza(p)
}
return (
<Aux>
{setModal(true) ?
<Backdrop clicked={toggleModalHandler} /> : null}
{setModal(true) ?
<Modal
clicked={toggleModalHandler}
ingredients={selectedPizza.ingredients}
price={selectedPizza.price}
image={selectedPizza.image}
name={selectedPizza.name}
/> : null}
<div className={styles.Pizza} id="pizza">
<h1>Pizza</h1>
<div className={styles.PizzaContainer}>
{pizzaproducts.map(p => {
return <div>
<div className={styles.PizzaCard}>
<div className={styles.PizzaCardHeader}>
<img src={p.image} alt="pizza" />
<h1>{p.name}</h1>
<p>{p.ingredients}</p>
</div>
<div className={styles.PizzaCardFooter}>
<h3>from ₦{p.price}</h3>
<button onClick={() => toggleModalHandler(p)}>Select</button>
</div>
</div>
</div>
})}
</div>
</div>
</Aux>
)
}
export default Pizzas;
How best can I convert this? I am guessing this error is from the togglemodalhandler. I am new to hooks.
You shouldn't set state inside the template. This triggers re-render, what again, trigger setting state and next...
Try something like this:
import React, { useState, useContext } from 'react';
const Pizzas = () => {
const [showModal, setModal] = useState(false);
const [selectedPizza, setSelectedPizza] = useState(null)
const { pizzaproducts } = useContext(ProductsContext)
const toggleModalHandler = (p) => {
setModal(true);
setSelectedPizza(p)
};
return (
<Aux>
{showModal ? <Backdrop clicked={toggleModalHandler} /> : null}
{showModal ?
<Modal
clicked={toggleModalHandler}
ingredients={selectedPizza.ingredients}
price={selectedPizza.price}
image={selectedPizza.image}
name={selectedPizza.name}
/> : null}
<div className={styles.Pizza} id="pizza">
<h1>Pizza</h1>
<div className={styles.PizzaContainer}>
{pizzaproducts.map(p => {
return <div>
<div className={styles.PizzaCard}>
<div className={styles.PizzaCardHeader}>
<img src={p.image} alt="pizza" />
<h1>{p.name}</h1>
<p>{p.ingredients}</p>
</div>
<div className={styles.PizzaCardFooter}>
<h3>from ₦{p.price}</h3>
<button onClick={() => toggleModalHandler(p)}>Select</button>
</div>
</div>
</div>
})}
</div>
</div>
</Aux>
)
}
export default Pizzas;
You are conditionally attempting to render using setModal(true)?, which is incorrect, should be showModal?
useState returns a pair of values: the current state and a function that updates it. This is why we write const [showModal, setModal] = useState(). This is similar to this.state.showModal and this.setState in a class, except you get them in a pair.
I have built a portfolio website with react here https://andrewkaras.me, but on selected work section you will notice lags when scrolling through project images (especially on Safari).
Here is the code for the projects container and for individual projects:
Myprojects:
import React from 'react'
import colors from '../../assets/colors.png'
import colorsWebp from '../../assets/colors.webp'
import crwn from '../../assets/crwn.png'
import crwnWebp from '../../assets/crwn.webp'
import devchat from '../../assets/devchat.png'
import devchatWebp from '../../assets/devchat.webp'
import movies from '../../assets/movies.png'
import moviesWebp from '../../assets/movies.webp'
import Project from '../../Components/Project/Project'
import styles from './MyProjects.module.scss'
const MyProjects = () => {
return (
<div className={styles.container} id="myProjects">
<div className={styles.myProjects}>
<div className={styles.headerWrapper}>
<h2 className={styles.header}>Selected Work</h2>
</div>
<Project
name="CRWN Clothing"
image={crwn}
imageWebp={crwnWebp}
color="rgb(157, 169, 238)"
hoverColor="rgb(177, 189, 258)"
link="crwnclothing.andrewkaras.me"
githubLink="https://github.com/Justbigmack/CRWN-Clothing"
text="An e-commerce web-app that allows you to easily purchase clothes. Payments are processed via Stripe API. It is built with React, Redux, Redux-Sagas and Firebase"
/>
<Project
right
name="React Colors"
image={colors}
imageWebp={colorsWebp}
project="colors"
color="rgb(161, 106, 195)"
hoverColor="rgb(181, 126, 215)"
link="colors.andrewkaras.me"
githubLink="https://github.com/Justbigmack/react-colors"
text="React Colors is an app allowing you to generate color palettes for your projects by leveraging easy to use UI and drag and drop system. The project is put together using React, CSS in JS, Material UI and features some React Router animations"
/>
<Project
name="DevChat"
image={devchat}
imageWebp={devchatWebp}
project="devchat"
color="rgb(251, 93, 81)"
hoverColor="rgb(271, 113, 101)"
link="devchat.andrewkaras.me"
githubLink="https://github.com/Justbigmack/dev-chat"
text="DevChat is a simplified clone of a well-known app - Slack. Devchat allows desktop and large tablet users to exchange messages, files and much more. The project is developed using React, Redux, Firebase and Semantic UI"
/>
<Project
right
name="React Movies"
image={movies}
imageWebp={moviesWebp}
project="movies"
color="rgb(134, 191, 211)"
hoverColor="rgb(154, 211, 231)"
link="movies.andrewkaras.me"
githubLink="https://github.com/Justbigmack/react-movies"
text="React Movies is a web-application that allows you to search for your favorite movies. It utilizes React Router and pulls information from TMDB via API"
/>
</div>
</div>
)
}
export default React.memo(MyProjects)
One project:
import React, { useState } from 'react'
import { ReactComponent as GithubIcon } from '../../assets/github.svg'
import styles from './Project.module.scss'
const Project = ({
name,
color,
hoverColor,
image,
imageWebp,
githubLink,
link,
right,
text
}) => {
const [hover, setHover] = useState(false)
const [hoverGH, setHoverGH] = useState(false)
return (
<div
className={right ? styles.projectContainerRight : styles.projectContainer}
>
<div className={styles.imageContainer} style={{ backgroundColor: color }}>
<picture>
<source type="image/webp" srcSet={imageWebp} />
<source type="image/png" srcSet={image} />
<img src={image} alt="Project of mine" />
</picture>
</div>
<div className={styles.projectTech}>Web-App</div>
<div className={styles.projectInfo}>
<h3 className={styles.projectName}>
{name}
<div className={styles.projectGithub}>
<a href={githubLink}>
<GithubIcon
onMouseEnter={() => {
setHoverGH(true)
}}
onMouseLeave={() => {
setHoverGH(false)
}}
className={styles.githubIcon}
style={
hoverGH
? {
fill: color
}
: {
fill: hoverColor
}
}
/>
</a>
</div>
</h3>
<h4 className={styles.projectText}>{text}</h4>
<a
className={styles.projectLink}
onMouseEnter={() => {
setHover(true)
}}
onMouseLeave={() => {
setHover(false)
}}
style={
hover
? {
color: color
}
: {
color: hoverColor
}
}
href={`https://${link}`}
>
{link}
</a>
</div>
</div>
)
}
export default React.memo(Project)
Everything is okay, if I add the same image to all projects, but as soon as I pass each project an individual image, it starts lagging on scroll. I am having trouble trying to figure out why.
Is it possible to render the matching data in the AutoComplete popover in the form of Tabs? I may have upto three categories of data matching the input value, that I'd like to display as tabs. Can I combine the Material-UI AutoComplete and Tabs components to achieve this?
The AutoComplete component creates a Menu component for the suggested items. So each suggestion is a component of type MenuItem.
MenuItem component could have dynamic children, and therefore you could add a tabs as the children of the MenuItem. The problem is that any click inside the suggestion popover closes the popover.
If you want to try it out, or maybe hack it somehow (like preventing the click event for tunneling to the popover, and handling the open state manually(?)), here is reproduction code (start typing the word "test" in the input to see suggestions):
import React from 'react';
import AutoComplete from 'material-ui/AutoComplete';
import {Tabs, Tab} from 'material-ui/Tabs';
import MenuItem from 'material-ui/MenuItem';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import {deepOrange500} from 'material-ui/styles/colors';
const muiTheme = getMuiTheme({
palette: {
accent1Color: deepOrange500,
},
});
export default class AutoCompleteExampleSimple extends React.Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
};
}
getTabs() {
return <MenuItem>
<Tabs>
<Tab label="Item One" >
<div>
<h2>Tab One</h2>
<p>
This is an example tab.
</p>
<p>
You can put any sort of HTML or react component in here. It even keeps the component state!
</p>
</div>
</Tab>
<Tab label="Item Two" >
<div>
<h2>Tab Two</h2>
<p>
This is another example tab.
</p>
</div>
</Tab>
<Tab
label="onActive"
route="/home">
<div>
<h2 >Tab Three</h2>
<p>
This is a third example tab.
</p>
</div>
</Tab>
</Tabs>
</MenuItem>
}
handleUpdateInput(value) {
this.setState({
dataSource: [
{text: 'test', value: this.getTabs()}
],
});
};
render() {
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<AutoComplete
hintText="Type anything"
dataSource={this.state.dataSource}
onUpdateInput={this.handleUpdateInput.bind(this)}
/>
</div>
</MuiThemeProvider>
);
}
}