React Hooks trying to useState in array ref - javascript

I'm trying to work with Hooks in react but i have a doubt about useState and References. My problem is because i want to create multiple references in my jsx but i dont know how use the usestate like a Array, well in the insert of the usestate data.
import React, { useState, useEffect } from "react";
import { Row, Col, Image, ListGroup, Container } from "react-bootstrap";
import AOS from "aos";
import "./css/App.css";
import "aos/dist/aos.css";
import Skills from "./Components/Skills";
import Work from "./Components/Work";
const App = () => {
const [ref, setRef] = useState([]);
useEffect(() => {
AOS.init({
duration: 2000
});
});
function handleOnClick(event) {
ref.scrollIntoView();
}
return (
<div className="App">
<Row>
<Col className="menu text-center" lg={4}>
<div className="picture">
<Image
src={process.env.PUBLIC_URL + "/Images/picture.jpg"}
roundedCircle
/>
</div>
<h1 className="menu-name">Fulanito Detal</h1>
<h4 className="menu-office">Software Engineer - Web Developer</h4>
<div>
<Row>
<Col lg={3}></Col>
<Col lg={6} className="menu-text">
<ListGroup>
<ListGroup.Item
onClick={event => handleOnClick(event)}
active
>
ABOUT
</ListGroup.Item>
<ListGroup.Item>WORK EXPERIENCE</ListGroup.Item>
<ListGroup.Item>EDUCATION</ListGroup.Item>
<ListGroup.Item>SKILLS</ListGroup.Item>
<ListGroup.Item>CONTACT</ListGroup.Item>
</ListGroup>
</Col>
<Col lg={3}></Col>
</Row>
</div>
</Col>
<Col className="info text-center" lg={8}>
<Container>
<div className="about"></div>
<div
className="work"
ref={ref => {
setRef(ref);
}}
>
<Work />
</div>
<div className="education"></div>
<div
className="skills"
ref={ref => {
setRef(ref);
}}
>
<Skills />
</div>
<div className="contact"></div>
</Container>
</Col>
</Row>
</div>
);
};
export default App;
The ref works fine just with one. If clicked about redirect to skills, but i want to use state like array to work with all references but i'm stuck with this one. Thanks for any help!

Here is a simplified example of using the useRef hook:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const App = () => {
const work = React.useRef();
const skills = React.useRef();
return (
<div>
<button onClick={() => work.current.scrollIntoView()}>
WORK EXPERIENCE
</button>
<button onClick={() => skills.current.scrollIntoView()}>SKILLS</button>
<div className="another" />
<div className="work" ref={work}>
WORK SECTION
</div>
<div className="skills" ref={skills}>
SKILL SECTIONS
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Related

Passing function from child to parent component in react-redux

I have encouneterd a problem that cannot find a solution in react-redux! I have a function that lives on Child component: "onClick={() => addToCart(product)}" Everytime I click on the button on UI of the application an error pops up saying: "TypeError: addToCart is not a function". I have tried several workarounds but in vain:
Parent component code:
class Jeans extends Component {
render () {
return (
<>
<PanelHeader size="sm" />
<ProductList
addToCart = {this.addToCart}
products={jeans}
image={jeans1}
header='Jeans For Men'
description='Foundation Of Contemporary Wardrobes,
Whether Tailored Or Super Skinny, Straight or Slim,
Biker or Destroyed, Our Denim Collection Caters To
Every Style And Silhouette.'
/>
</>
);
}
}
const mapStateToProps = (state)=> {
return {
products: state.products
}
}
const mapDispatchToProps = (dispatch) => {
return {
addToCart: (id) => {dispatch(addToCart(id))}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Jeans);```
and Child component where the function lives:
```class ProductCard extends Component {
render() {
const {image, product, key, addToCart} = this.props
return (
<Col
lg={4}
md={6}
sm={6}
xs={12}
className="font-icon-list"
key={key}
><Card>
<CardImg img src={image} alt="product"/>
<CardBody>
<CardTitle className='d-inline align-middle text-danger'>{product.title}</CardTitle>
<CardTitle className='d-inline align-middle float-right h5'><strong>{product.price}</strong></CardTitle>
<CardText className='my-2'>{product.description}</CardText>
<Button>
<div className="col-md-12 text-center">
<div className="buttons d-flex flex-row">
<div className="cart"><i className="fa fa-shopping-cart"></i>
</div>
<button onClick={() => addToCart(product)} className="btn btn-success cart-button px-5">Add to Cart</button>
</div>
</div>
</Button>
</CardBody>
</Card>
</Col>
)
}
}
export default ProductCard```
**Thank you in advance for your time reviewing my question!**
There is an intermediate component between Parent (Jeans) and Child (Productcard) called (Productlist) so the order goes: "Jeans" --> "ProductList" --> "ProductCard".
ProductList component:
const ProductList = ({products, header, description, image, addToCart}) => {
return (
<div className="content">
<Row>
<Col md={12}>
<Card>
<CardHeader>
<h5 className="title">{header}</h5>
<p className="category">{description}</p>
</CardHeader>
<CardBody className="all-icons">
<Row>
{products.map((product, key) => {
return (
<ProductCard
addToCart = {addToCart}
key={key}
product={product}
image={image}
/>
);
})}
</Row>
</CardBody>
</Card>
</Col>
</Row>
</div>
);
}
export default ProductList;```
index.js consists of the following code:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.css";
import "assets/scss/now-ui-dashboard.scss?v1.5.0";
import "assets/css/demo.css";
import { Provider } from "react-redux";
import AdminLayout from "layouts/Admin.js";
import store from "./redux/store"
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route path="/admin" render={(props) => <AdminLayout {...props} />} />
<Redirect to="/admin/dashboard" />
</Switch>
</BrowserRouter>
</Provider>,
document.getElementById("root")
);

React.js i wanna put parameter in Toast UI Viewer

i just show my texts with toast-editor-viewer
( here is link. https://github.com/nhn/tui.editor/blob/master/apps/react-editor/src/viewer.js)
but don't have initialValue!!!
{Classs.content} is ok
because i checked in <textarea value={Classs.content} readOnly="readOnly" style={{display:"none"}}></textarea>
how can i get {Classs.content} into initialValue
import React,{useEffect,useLayoutEffect, useState,useRef} from 'react'
import { useDispatch } from "react-redux";
import {videoclassdetail} from "../../_actions/index"
import ProductInfo from './ProductInfo';
import { Row, Col } from 'antd';
import ReactDOM from 'react-dom';
import 'codemirror/lib/codemirror.css';
import '#toast-ui/editor/dist/toastui-editor.css';
import { Viewer } from '#toast-ui/react-editor';
import PayButton from './PayButton';
import ClassButton from './ClassButton';
function ClassDetailPage(props) {
const editorRef = useRef()
const dispatch = useDispatch();
const classId = props.match.params.classId
const [Classs, setClasss] = useState({})
const asdasd = (
<Viewer
viewer="true"
// el= {document.querySelector('#viewer')}
height="500px"
initialValue={Classs.content}/>
)
useEffect(() => {
dispatch(videoclassdetail(classId))
.then((res) => {
console.log(res.payload);
setClasss(res.payload)
console.log(res.payload.content);
})
}, [dispatch])
return (
<div style={{ width: '100%', padding: '3rem 4rem'}}>
<div >
<textarea value={Classs.content} readOnly="readOnly" style={{display:"none"}}></textarea>
<div >
{asdasd}
</div>
<Row gutter={[16, 16]} >
<Col lg={18} sm={24}>
</Col>
<Col lg={6} sm={24}>
{/* ProductInfo */}
<ProductInfo detail={Classs} />
</Col>
</Row>
</div>
<br/>
<div>
{/* {Button} */}
{/* <button onClick={clickHandler}>add to cart</button> */}
</div>
</div>
)
}
export default ClassDetailPage
here

How to create an Order Summary Component

I'd like to create an order summary component on the right hand side as shown below: How the UI looks
However, I'm not sure how to go about this as I am quite new to MERN stack. This is the component for the how the restaurant details are displayed:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Grid, CircularProgress } from "#material-ui/core";
import useStyles from "./styles";
import { useParams } from "react-router-dom";
import { restaurantDetails } from "../../actions/restaurants";
import { TextField, Button, Typography, Paper } from "#material-ui/core";
import { LinearProgress } from "#material-ui/core";
import { Container, Row, Col } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.css";
import OrderSummary from "./OrderSummary/OrderSummary";
const RestaurantDetails = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
let { _id } = useParams();
const [restaurantInfo, setRestaurantInfo] = useState();
useEffect(() => {
try {
dispatch(restaurantDetails(_id)).then((res) => setRestaurantInfo(res));
console.log("this is restaurantInfo" + restaurantInfo);
console.log(_id);
} catch (e) {
console.error(e);
}
}, [dispatch]);
return !restaurantInfo ? (
<CircularProgress />
) : (
<Container>
<LinearProgress variant="determinate" value="20" color="secondary" />;
<Row>
<Col sm={8}>
{" "}
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Paper className={classes.paper}>{restaurantInfo.name} </Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>{restaurantInfo.categoryname1}</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>{restaurantInfo.categoryname2}</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName11}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice11}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName12}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice12}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName21}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice21}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName22}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice22}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
</Grid>
</div>
</Col>
<OrderSummary />
</Row>
</Container>
// <div>
// <h2>Restaurant id is: {_id}</h2>
// <h2>Restaurant name is: {restaurantInfo.name}</h2>
// </div>
);
};
export default RestaurantDetails;
This is the Order Summary component at the moment. Obviously, I would like to display the item names and prices when they are added in order to checkout
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Grid, CircularProgress } from "#material-ui/core";
import useStyles from "./styles";
import { Row, Col } from "react-bootstrap";
import { TextField, Button, Typography, Paper } from "#material-ui/core";
import Card from "#material-ui/core/Card";
import CardContent from "#material-ui/core/CardContent";
import CardHeader from "#material-ui/core/CardHeader";
import CardActions from "#material-ui/core/CardActions";
import { Divider } from "#material-ui/core";
import "bootstrap/dist/css/bootstrap.css";
const OrderTotal = () => {
const classes = useStyles();
return (
<div>
<Col sm={4}>
{" "}
<Card className={classes.root}>
<CardHeader title="Order Summary" className={classes.header} />
<Divider variant="middle" />
<CardContent>
<div className={classes.list}>
<Row>
<Col sm={6}>
<Typography align="center">Display Item</Typography>
</Col>
<Col sm={6}>
<Typography align="center">Display Prices</Typography>
</Col>
</Row>
</div>
</CardContent>
<Divider variant="middle" />
<CardActions className={classes.action}>
<Button variant="contained" color="primary" className={classes.button}>
Order Now
</Button>
</CardActions>
</Card>
</Col>
</div>
);
};
export default OrderTotal;
How do I implement this? How do I pass the prices and names to the order summary component and list them whenever they are added or deleted? I will really appreciate it as I can't seem to figure this out!
You need to store the current cart items in the redux state. You will need an action that adds an item to the cart. Your reducer needs to handle this action and update the cart data. Here is a very basic implementation:
const orderSlice = createSlice({
name: 'order',
initialState: {
items: [],
status: 'unsubmitted'
},
reducers: {
addToOrder: (state, action) => {
state.items.push(action.payload);
},
submitOrder: (state) => {
state.status = 'pending';
}
}
})
export const orderReducer = orderSlice.reducer;
export const {addToOrder, submitOrder} = orderSlice.actions;
Your "Add To Order" Button needs an onClick handler that dispatches your action.
<Button
variant="contained"
color="secondary"
onClick={() => dispatch(addToOrder({
name: restaurantInfo.itemName12,
price: restaurantInfo.itemPrice12
}))}
>
Add To Order
</Button>
Your OrderTotal component would use a useSelector hook to access the cart data from redux.
const orderItems = useSelector(state => state.order.items);
const orderTotal = orderItems.reduce((total, item) => total + item.price, 0);
As a sidenote, you probably should not store restaurantInfo in your component state since it seems like it's already being set in redux. Instead you should access it with a useSelector.

Why does a useCallback option have to be called with a class component in Reactjs?

I am stumped. I have been trying to get a simple cleartext button to work. I have tried all the option available on this platform but nothing is working for me. React Hook useCallback cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook. I have no idea why this error is occurring. I am pretty new to react can anyone please help? I am trying to clear the text on a click of the clear button.
import React, { Component, useCallback, useState } from "react";
import {
Button,
Input,
Footer,
Card,
CardBody,
CardImage,
CardTitle,
CardText
} from "mdbreact";
import blankImg from "./blank.gif";
import "./style.css";
import "./flags.min.css";
import countriesList from "./countries.json";
class App extends Component {
state = {
search: ""
};
renderCountry = country => {
const { search } = this.state;
var code = country.code.toLowerCase();
const handleClick = useCallback(() => {
e.target.value = '';
}, []);
return (
<div className="col-md-3" style={{ marginTop: "20px" }}>
<Card>
<CardBody>
<p className="">
<img
src={blankImg}
className={"flag flag-" + code}
alt={country.name}
/>
</p>
<CardTitle title={country.name}>
{country.name.substring(0, 15)}
{country.name.length > 15 && "..."}
</CardTitle>
</CardBody>
</Card>
</div>
);
};
onchange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const filteredCountries = countriesList.filter(country => {
return country.name.toLowerCase().indexOf(search.toLowerCase()) !== -1;
});
return (
<div className="flyout">
<main style={{ marginTop: "4rem" }}>
<div className="container">
<div className="row">
<div className="col">
<Input
label="Search Country"
icon="search"
onChange={this.onchange}
/>
<button onClick={handleClick}> Click to clear</button>
</div>
<div className="col" />
</div>
<div className="row">
{filteredCountries.map(country => {
return this.renderCountry(country);
})}
</div>
</div>
</main>
<Footer color="indigo">
<p className="footer-copyright mb-0">
© {new Date().getFullYear()} Copyright
</p>
</Footer>
</div>
);
}
}
export default App;
It is because you try to use hooks in a class based component. You can only use hooks like useCallback in functional components. Therefore you are mixing the concepts of object oriented and functional programming.
The following should do the trick:
import React, { Component, useCallback, useState } from "react";
import {
Button,
Input,
Footer,
Card,
CardBody,
CardImage,
CardTitle,
CardText
} from "mdbreact";
import blankImg from "./blank.gif";
import "./style.css";
import "./flags.min.css";
import countriesList from "./countries.json";
class App extends Component {
state = {
search: ""
};
const handleClick = (e) => {
e.target.value = '';
};
renderCountry = country => {
const { search } = this.state;
var code = country.code.toLowerCase();
return (
<div className="col-md-3" style={{ marginTop: "20px" }}>
<Card>
<CardBody>
<p className="">
<img
src={blankImg}
className={"flag flag-" + code}
alt={country.name}
/>
</p>
<CardTitle title={country.name}>
{country.name.substring(0, 15)}
{country.name.length > 15 && "..."}
</CardTitle>
</CardBody>
</Card>
</div>
);
};
onchange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const filteredCountries = countriesList.filter(country => {
return country.name.toLowerCase().indexOf(search.toLowerCase()) !== -1;
});
return (
<div className="flyout">
<main style={{ marginTop: "4rem" }}>
<div className="container">
<div className="row">
<div className="col">
<Input
label="Search Country"
icon="search"
onChange={this.onchange}
/>
<button onClick={this.handleClick}> Click to clear</button>
</div>
<div className="col" />
</div>
<div className="row">
{filteredCountries.map(country => {
return this.renderCountry(country);
})}
</div>
</div>
</main>
<Footer color="indigo">
<p className="footer-copyright mb-0">
© {new Date().getFullYear()} Copyright
</p>
</Footer>
</div>
);
}
}
export default App;
useCallback hooks can only be used in functional components OR in a custom Hook NOT in class components.
You have declared your App component in class based approach i.e. Object oriented approach. To use useCallback hook for this, you should change your App component declaration to a functional component or Custom hook.
Something like this
function App() {
return (
<>Hello World!</>
);
}
you cannot useCallBack hook in class Component,we can do a simple thing to clear the button text, by using
a button text state, i.e. { btnTxt: "Clear ButtonText"} than update the state onclick
import React, { Component, useCallback, useState } from "react";
import {
Button,
Input,
Footer,
Card,
CardBody,
CardImage,
CardTitle,
CardText
} from "mdbreact";
import blankImg from "./blank.gif";
import "./style.css";
import "./flags.min.css";
import countriesList from "./countries.json";
class App extends Component {
state = {
search: "",
btnTxt: "Clear ButtonText"
};
renderCountry = country => {
const { search } = this.state;
var code = country.code.toLowerCase();
return (
<div className="col-md-3" style={{ marginTop: "20px" }}>
<Card>
<CardBody>
<p className="">
<img
src={blankImg}
className={"flag flag-" + code}
alt={country.name}
/>
</p>
<CardTitle title={country.name}>
{country.name.substring(0, 15)}
{country.name.length > 15 && "..."}
</CardTitle>
</CardBody>
</Card>
</div>
);
};
onchange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const filteredCountries = countriesList.filter(country => {
return country.name.toLowerCase().indexOf(search.toLowerCase()) !== -1;
});
return (
<div className="flyout">
<main style={{ marginTop: "4rem" }}>
<div className="container">
<div className="row">
<div className="col">
<Input
label="Search Country"
icon="search"
onChange={this.onchange}
/>
<button onClick={()=> this.setState({btnText:""})}> {this.state.btnTExt}</button>
</div>
<div className="col" />
</div>
<div className="row">
{filteredCountries.map(country => {
return this.renderCountry(country);
})}
</div>
</div>
</main>
<Footer color="indigo">
<p className="footer-copyright mb-0">
© {new Date().getFullYear()} Copyright
</p>
</Footer>
</div>
);
}
}
export default App;

React Hooks to filter through list

I am using react/redux & would like to filter through posts that are from my backend in Node. I am mapping through the posts and they are being shown. Trying to implement a filter input I am looking for some advice on how to use react hooks to get this working.
My component...
import React, { Fragment, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import Spinner from '../layout/Spinner';
import { getCommunityPosts } from '../../actions/communitypost';
import CommunityPostItem from './CommunityPostItem';
import Cooking from '../../img/vegetables.jpg';
import Lifestyle from '../../img/lifestyle.jpg';
import General from '../../img/general.jpg';
// Lazy load
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';
const CommunityPosts = ({
getCommunityPosts,
communitypost: { posts, loading }
}) => {
const [searchTerm, setSearchTerm] = useState("");
const [searchPosts, setSearchPosts] = useState([]);
const handleChange = e => {
setSearchTerm(e.target.value);
}
useEffect(() => {
const results = posts.filter(post => {
console.log(post);
post.toLowerCase().includes(searchTerm)
}
);
setSearchPosts(results)
getCommunityPosts();
}, [getCommunityPosts, searchTerm]);
return (
loading ? (
<Spinner />
) : (
<Fragment>
<Fragment>
<div className="search-recipes">
<input
className="bg-white focus:outline-none focus:shadow-outline border border-gray-300 rounded-lg py-2 px-4 block w-full appearance-none leading-normal"
type="text"
value={searchTerm}
onChange={handleChange}
placeholder="Search community posts..."
></input>
</div>
<div className="pt-1 grid lg:grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-1">
<div className="cursor-pointer category-overlay">
<Fragment>
<Link to="/communityposts/category/cooking">
<LazyLoadImage effect="blur" src={Cooking}></LazyLoadImage>
<div className="content">
<div className="recipe-category-text pacifico">Cooking</div>
</div>
</Link>
</Fragment>
</div>
<div className="cursor-pointer category-overlay">
<Fragment>
<Link to="/communityposts/category/lifestyle">
<LazyLoadImage effect="blur" src={Lifestyle}></LazyLoadImage>
<div className="content">
<div className="recipe-category-text pacifico">Lifestyle</div>
</div>
</Link>
</Fragment>
</div>
<div className="cursor-pointer category-overlay">
<Fragment>
<Link to="/communityposts/category/general">
<LazyLoadImage effect="blur" src={General}></LazyLoadImage>
<div className="content">
<div className="recipe-category-text pacifico">General</div>
</div>
</Link>
</Fragment>
</div>
</div>
</Fragment>
<Fragment>
<div className="community-posts bg-gray-200">
{posts.map(post => (
<CommunityPostItem key={post._id} post={post} />
))}
</div>
</Fragment>
</Fragment>
)
);
};
CommunityPosts.propTypes = {
getCommunityPosts: PropTypes.func.isRequired,
communitypost: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
communitypost: state.communitypost
});
export default connect(mapStateToProps, { getCommunityPosts })(CommunityPosts);
Error i'm getting is that "TypeError: post.toLowerCase is not a function"

Categories