Refactoring jQuery for react component - javascript

I am moving away from using jQuery to do some quick hides, shows and css changes because I am using components in react that need to be re-rendered and thus are not triggering the jQuery actions that need a page refresh. I think my issue is that I need to set the state in each component but I am a bit confused as to how. Here is an example of the jquery for this particular view:
<script type="text/javascript">
$(document).ready(function () {
$(".schedule-times").hide();
$(".final-check").hide();
$(".available-time").on('click', function () {
$(".schedule-times").toggle();
});
$(".schedule-button").on('click', function () {
$('.finalize-timeline').css("background", "#4CAF50");
$(".final-check").show();
});
});
</script>
Here is an example of a component I have written:
import React, { Component } from 'react';
import '../../App.css';
import Calendar from '../Calendar';
import { Link } from 'react-router';
class Schedule_3 extends Component {
render() {
return (
<div className="wow fadeIn">
<div className="container">
<div className="timeline">
<div className="col-md-12 offset-md-2">
<div className="row">
<div className="col-md-2 timeline-box">
<div className="timeline-badge active-timeline">
<i className="fa fa-check wow bounceInDown"></i>
</div>
<span>How do you want to schedule?</span>
</div>
<div className="col-md-2 timeline-box">
<div className="timeline-badge active-timeline">
<i className="fa fa-check wow bounceInDown"></i>
</div>
<span>Pick your lesson type</span>
</div>
<div className="col-md-2 timeline-box">
<div className="timeline-badge active-timeline">
</div>
<span>Find a time</span>
</div>
<div className="col-md-2 timeline-box">
<div className="timeline-badge" id="no_border">
</div>
<span>Finalize</span>
</div>
</div>
</div>
</div>
<div className="row">
<div className="container">
<div className="col-md-6 offset-md-3">
<Calendar />
</div>
</div>
</div><br />
<div className="row schedule-times">
<div className="col-md-12 offset-md-2">
<div className="row">
<div className="col-md-4 offset-md-1">
<i className="fa fa-clock"></i>
10:30AM
</div>
<div className="col-md-2 offset-md-1">
<Link to="Schedule_4">
<button className="btn btn-primary">
Book Now
</button>
</Link>
</div>
</div><br />
<div className="row">
<div className="col-md-4 offset-md-1">
<i className="fa fa-clock"></i>
11:00AM
</div>
<div className="col-md-2 offset-md-1">
<button className="btn btn-primary">
Book Now
</button>
</div>
</div><br />
<div className="row">
<div className="col-md-4 offset-md-1">
<i className="fa fa-clock"></i>
11:30AM
</div>
<div className="col-md-2 offset-md-1">
<button className="btn btn-primary">
Book Now
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Schedule_3;

Looking at your code I would suggest the first thing you need to do is split it into smaller, more manageable and more readable components that are responsible for 1 thing.
As you have posted a big example I cannot show you how to do it for every case you have, but I can give you a simple example that can be adapted for your use cases.
class ToggleContent extends React.Component {
constructor() {
super();
this.state = { hidden: true };
this.toggleContent = this.toggleContent.bind(this);
}
toggleContent() {
this.setState(prevState => ({
hidden: !prevState.hidden
}));
}
render() {
const { hidden } = this.state;
const { children } = this.props;
return (
<div>
<button onClick={ this.toggleContent }>Toggle</button>
<div>
{ !hidden && children }
</div>
</div>
);
}
}
You can use this component like this <ToggleContent>Hello World</ToggleContent> and it will toggle visibility of Hello World on the button press. You can put anything inside of this, including other components, it doesn't have to just be text.
You can see an example of it running here.
You can see the state of whether the children are hidden or not is held in the component this.state = { hidden: true };.
The children are then rendered if it is not hidden, if !hidden === true. We can see that inline here { !hidden && children }.
The toggleContent method is then using the previous state to switch back and forth between hidden and showing.
toggleContent() {
this.setState(prevState => ({
hidden: !prevState.hidden
}));
}

Related

Change boolean value onClick in React

I'm trying to change the value of a boolean from an object imported from a JSON file in React. I want the offers.availability value to change to false after clicking on the "add to cart" button.
Here's my code:
function App() {
class App {
constructor () {
this.state = {
offers: [],
}
this.handleToggle = this.handleToggle.bind(this);
}
componentDidMount() {
this.state.setState({ offers: Data });
}
handleToggle (offers) {
this.setState(prevState => ({
offers: prevState.offers.map(prevOffer => {
if (prevOffer.availability === offers.availability) {
return {
availability: prevOffer.availability,
isTrue: !prevOffer.isTrue
}
}
return prevOffer;
})}));
}
}
return (
<div className="container">
<div className="row">
{Data.offers.map(offers => {
return(
<div key={offers.make + offers.model + offers.engine + offers.photo} className="col-sm-4">
<div className="card" >
<img src={offers.photo} className="card-img-top" alt={offers.make + ' ' + offers.model } width="100%"/>
<div className="card-body pt-0 px-0">
<div className="d-flex flex-row justify-content-between mb-0 px-3 p-3 mid">
<div className="d-flex flex-column">
<h4>{offers.make} {offers.model}</h4>
</div>
<div className="d-flex flex-column">
<button type="button" className="btn btndelete"><FaTrash /></button>
</div>
</div>
<div className="d-flex flex-row justify-content-between px-3">
<div className="d-flex flex-column"><span className="text-muted">Engine: {offers.engine}</span></div>
<div className="d-flex flex-column">
{offers.availability.toString()}
</div>
</div>
<div className="mx-3 mt-3 mb-2 d-grid gap-2">
{offers.availability
? <button type="button" className="btn btn-primary addtocartbtn" onClick={() => Data.offers.handleToggle(offers)}>
<small>Add to cart</small>
</button>
: <button type="button" className="btn btn-disabled" onClick={console.log('???')}><small>Currently unavailabe</small></button>
}
</div>
</div>
</div>
</div>
)
}) }
</div>
</div>
)}
export default App;
I tried to toggle the boolean value but I currently get a ".offers.handleToggle is not a function" error after clicking.
I'm new to this so please don't judge if I did something really stupid here :) What could be the possible solution to this?
You should not use Data.offers.handleToggle. From what I see, Data.offers is an array of objects which they don't have a function handleToggle defined.
However, you are defining a function handleToggle on the App component that looks good. It should work if you change onClick={() => Data.offers.handleToggle(offers)} with either onClick={() => handleToggle(offers)} or onClick={() => this.handleToggle(offers)}
UPDATE
After running your code I saw the component is defined as a mix of a functional component and a class component. First, decide what you are going to use and then fix the errors 1 by 1. The constructor for example is missing the props, there are onclicks that are not well defined and a few more things.
Here is your code if used as a class component.
import { Component } from "react";
export class App extends Component<{}, { offers: any[] }> {
constructor(props: {}) {
super(props);
this.state = {
offers: [],
};
this.handleToggle = this.handleToggle.bind(this);
}
componentDidMount() {
this.setState({ offers: Data });
}
handleToggle(offers: any) {
this.setState((prevState) => ({
offers: prevState.offers.map((prevOffer) => {
if (prevOffer.availability === offers.availability) {
return {
availability: prevOffer.availability,
isTrue: !prevOffer.isTrue,
};
}
return prevOffer;
}),
}));
}
render() {
return (
<div className="container">
<div className="row">
{this.state.offers.map((offers) => {
return (
<div
key={offers.make + offers.model + offers.engine + offers.photo}
className="col-sm-4"
>
<div className="card">
<img
src={offers.photo}
className="card-img-top"
alt={offers.make + " " + offers.model}
width="100%"
/>
<div className="card-body pt-0 px-0">
<div className="d-flex flex-row justify-content-between mb-0 px-3 p-3 mid">
<div className="d-flex flex-column">
<h4>
{offers.make} {offers.model}
</h4>
</div>
<div className="d-flex flex-column">
<button type="button" className="btn btndelete">
<FaTrash />
</button>
</div>
</div>
<div className="d-flex flex-row justify-content-between px-3">
<div className="d-flex flex-column">
<span className="text-muted">
Engine: {offers.engine}
</span>
</div>
<div className="d-flex flex-column">
{offers.availability.toString()}
</div>
</div>
<div className="mx-3 mt-3 mb-2 d-grid gap-2">
{offers.availability ? (
<button
type="button"
className="btn btn-primary addtocartbtn"
onClick={() => this.handleToggle(offers)}
>
<small>Add to cart</small>
</button>
) : (
<button
type="button"
className="btn btn-disabled"
onClick={() => console.log("???")}
>
<small>Currently unavailabe</small>
</button>
)}
</div>
</div>
</div>
</div>
);
})}
</div>
</div>
);
}
}
You just need to define the offers type and a FaTrash component

Filter not working proper in react its working only for first time also how to filter true and false

Here is my code
https://stackblitz.com/edit/react-nsxxqp?file=src%2FApp.js
and my local code is here how to filter i don't know i am new for react and JavaScript please help me i don't know how to finish my task.
import React, { useEffect, useState } from "react";
const Product = (props) => {
const [allButtons, setAllButtons] = useState([]);
const [product, setProduct] = useState([]);
useEffect(() => {
fetch("https://api.spacexdata.com/v3/launches?limit=100")
.then(response => response.json())
.then(productsList => {
setProduct(productsList);
setAllButtons(productsList);
});
}, []);
const onBtnClick = (e) =>{
setProduct(product.filter(i=>i.launch_year == e));
};
return(
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<h2>SpacesX Launch Programme</h2>
</div>
</div>
<div className="row">
<div className="col-xl-2 col-lg-2 col-md-2 col-sm-2 col-xs-12">
<div className="inner">
<p className="bold">Filter</p>
<div className="col12 launchYear">
<p className="marg0">Launch Year</p>
{allButtons.map(productYr => (
<button
className="btn btn-primary btnSpacex"
key={productYr.launch_year}
onClick={(e) => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))}
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Launch</p>
<button className="btn btn-default btnSpacex">True</button>
<button className="btn btn-default btnSpacex">False</button>
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Landing</p>
<button className="btn btn-default btnSpacex">True</button>
<button className="btn btn-default btnSpacex">False</button>
</div>
</div>
</div>
<div className="col-xl-10 col-lg-10 col-md-10 col-sm-10 col-xs-12 items1">
<div className="row">
{product.map(product => (
<div
key={product.flight_number}
className="col-xl-3 col-lg-3 col-md-3 col-sm-3 col-xs-12 marginBottom15"
>
<div className="inner">
<img
src={product.links.mission_patch}
className="full-width imgBg"
alt={product.mission_name}
/>
<div className="clearfix" />
<p className="productName bold margBot5">
{product.mission_name} #{product.flight_number}
</p>
<div className="clearfix" />
<p className="bold margBot5">
Mission Ids:
<ul className="marg0 blueClr">
<li>{product.mission_id}</li>
</ul>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Launch Year:{" "}
<span className="normal blueClr">
{product.launch_year}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Launch:{" "}
<span className="normal blueClr">
{product.launch_success}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Landing:{" "}
<span className="normal blueClr">
{product.rocket.land_success}
</span>
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
)
}
export default Product
Main issue here is your onButtonClick function. Change it to the following code (instead of product.filter, use allButtons.filter):
const onBtnClick = e => {
setProduct(allButtons.filter(i => i.launch_year == e));
};
The problem was that you had all of your products, then when you selected the first button, you set the product to just that button. On the next click, you're trying to filter on just the single product that you selected in the first click. To get around this, you want the filter to always be on the allButtons list (I'm assuming this was just a small oversight on your part, it looks like you knew exactly what you were trying to do but just accidentally put the wrong list in the function).
Another small change that I would make to your code is below: (introduce index parameter and use it as the key):
{allButtons.map((productYr, index) => (
<button
className="btn btn-primary btnSpacex"
key={index}
onClick={e => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))
}
This will eliminate all those console warnings that you're getting for having duplicate keys.
Check below code
import React, { useEffect, useState } from "react";
const Product = (props) => {
const [allButtons, setAllButtons] = useState([]);
const [launchSuccess, launchAllSuccess] = useState([]);
const [landSuccess, landAllSuccess] = useState([]);
const [product, setProduct] = useState([]);
useEffect(() => {
fetch("https://api.spacexdata.com/v3/launches?limit=100")
.then(response => response.json())
.then(productsList => {
setProduct(productsList);
setAllButtons(productsList);
launchAllSuccess(productsList);
landAllSuccess(productsList);
});
}, []);
const onBtnClick = e => {
setProduct(allButtons.filter(i => i.launch_year === e));
};
const onBtnLaunchAllSuccess = e =>{
setProduct(launchSuccess.filter(i => i.launch_success === e));
}
const onBtnLandSuccessful = e =>{
setProduct(landSuccess.filter(i => i.rocket.first_stage.cores[0].land_success === e));
}
return(
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<h2>SpacesX Launch Programme</h2>
</div>
</div>
<div className="row">
<div className="col-xl-2 col-lg-2 col-md-2 col-sm-2 col-xs-12">
<div className="inner">
<p className="bold">Filter</p>
<div className="col12 launchYear">
<p className="marg0">Launch Year</p>
{allButtons.map((productYr, index) => (
<button
className="btn btn-primary btnSpacex"
key={index}
onClick={e => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))
}
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Launch</p>
<button
onClick={e => onBtnLaunchAllSuccess(true)}
className="btn btn-default btnSpacex">True</button>
<button
onClick={e => onBtnLaunchAllSuccess(false)}
className="btn btn-default btnSpacex">False</button>
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Landing</p>
<button
onClick={e => onBtnLandSuccessful(true)}
className="btn btn-default btnSpacex">True</button>
<button
onClick={e => onBtnLandSuccessful(false)}
className="btn btn-default btnSpacex">False</button>
</div>
</div>
</div>
<div className="col-xl-10 col-lg-10 col-md-10 col-sm-10 col-xs-12 items1">
<div className="row">
{product.map(product => (
<div
key={product.flight_number}
className="col-xl-3 col-lg-3 col-md-3 col-sm-3 col-xs-12 marginBottom15"
>
<div className="inner">
<img
src={product.links.mission_patch}
className="full-width imgBg"
alt={product.mission_name}
/>
<div className="clearfix" />
<p className="productName bold margBot5">
{product.mission_name} #{product.flight_number}
</p>
<div className="clearfix" />
<p className="bold margBot5">
Mission Ids:
<ul className="marg0 blueClr">
<li>{product.mission_id}</li>
</ul>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Launch Year:
<span className="normal blueClr">
{product.launch_year}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Launch:
<span className="normal blueClr">
{product.launch_success}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Landing:
<span className="normal blueClr">
{product.rocket.first_stage.cores[0].land_success}
</span>
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
)
}
export default Product

How can I call a function inside of a .map of arrays?

I am passing down a function through props that capitalizes a few items being mapped over. I am getting an error on the item portion of item.creator.I am just wondering why I am recieving the error and not able to just call the function inside of the map. Thanks for your help.
Error message is Line Parsing error: Unexpected token, expected ",".
PARENT COMPONENT
export default function MainContent() {
const techContent = useSelector(displayTechContent);
const designContent = useSelector(displayDesignContent);
const makeCapital = (words) => words.replace(/^\w/, (c) => c.toUpperCase());
return (
<div className="container">
<div className="topics-list">
<div className="topic-row mb-5">
<h2 className="topic-heading mb-4">Software Development</h2>
<ContentCard data={techContent} capitalize={makeCapital} />
</div>
CHILD COMPONENT
export default (props) => (
<div>
<div className="resource-list">
{props.data.map((item) => (
<a key={item.id} href={item.link} className="resource-card-link mr-3">
<div className="card resource-card mb-2">
<div className="card-header">
<h4 className="resource-title">{item.title}</h4>
<span className="resource-creator">by: ***{props.capitalize({item.creator})}***.</span> <--this function
</div>
<div className="card-body py-3">
<div className="resource-description mb-2">
{item.description}
</div>
<div className="resource-type mb-2">
<i className="fas fa-book"></i> {item.type}
</div>
The curly braces around of item.creator are redundant.
export default (props) => (
<div>
<div className="resource-list">
{props.data.map((item) => (
<a key={item.id} href={item.link} className="resource-card-link mr-3">
<div className="card resource-card mb-2">
<div className="card-header">
<h4 className="resource-title">{item.title}</h4>
<span className="resource-creator">by: ***{props.capitalize(item.creator)}***.</span> <--this function
</div>
<div className="card-body py-3">
<div className="resource-description mb-2">
{item.description}
</div>
<div className="resource-type mb-2">
<i className="fas fa-book"></i> {item.type}
</div>

Click on Link to show details of item - ReactJs, Node.js

App is running on Node.js and React. In database (mongodb used) I have collection Rooms that contains details about particular room.
On LandingPage I display some of room details and to se more person has to click on View link.
LandingPage.js
const Room = props => (
<div className = "col-md-4" >
<div className="card mb-4 shadow-sm">
<img src={props.room.imageData} class="card-img-top" alt="..." width="100%" height="225" />
<div className="card-body">
<h5 class="card-title">{props.room.title}</h5>
<p className="card-text">{props.room.description}</p>
<div className="d-flex justify-content-between align-items-center">
<div className="btn-group">
<Link className="btn btn-sm btn-outline-secondary" to={"/view/"+props.room._id}>View</Link>
</div>
</div>
</div>
</div>
</div >
)
Link is sending me to view page
<Link className="btn btn-sm btn-outline-secondary" to={"/view/"+props.room._id}>View</Link>
But I am not sure how would I display now all details of room from database?
View.js
export default class RoomsAdmin extends React.Component {
constructor(props) {
super(props);
this.state = { rooms: [] };
}
componentDidMount() {
axios.get('http://localhost:3090/admin/')
.then(response => {
this.setState({
rooms: response.data
})
.catch(function (error) {
console.log(error);
})
})
}
roomList() {
return this.state.rooms.map(function (currentRoom, i) {
return <Room room={currentRoom} key={i} />
});
}
render() {
console.log(this.props);
return (
<div>
<div className="album py-5 bg-light">
<div className="container">
<div className="row">
<div className="col-md-4">
<div className="card mb-4 shadow-sm">
<img src={props.room.imageData} className="card-img-top" alt="..." width="100%" height="225" />
<div className="card-body">
<h5 class="card-title">{props.room.title}</h5>
<p className="card-text">{props.room.description}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
I came up with this code for now but I am getting following error:
Uncaught ReferenceError: props is not defined
Yes because you are writing props not this.props in your image tag.
In RoomAdmin Component
<img src={props.room.imageData} className="..../>
Use this instead
<img src={this.props.room.imageData} className=".../>

Slider issue in react js

I am integrating this template by converting its HTML to jsx.
I could not found the issue as there are no errors in the console. I already have a react developer tool in chrome.
Below is the code for slider in react slider component.
import React from 'react';
export default class Slider extends React.Component {
render() {
return (
<section className="section swiper-container swiper-slider swiper-classic bg-gray-2" data-loop="true" data-autoplay="4000" data-simulate-touch="false" data-slide-effect="fade">
<div className="swiper-wrapper">
<div className="swiper-slide" data-slide-bg="~/ClientApp/public/images/slider-1-slide-1-1920x671.jpg">
<div className="container">
<div className="swiper-slide-caption">
<h1 data-caption-animate="fadeInUp" data-caption-delay="100">Safe <br /> Betting</h1>
<h4 data-caption-animate="fadeInUp" data-caption-delay="200">With 100% Risk-Free Guarantee</h4><a className="button button-gray-outline" data-caption-animate="fadeInUp" data-caption-delay="300" href={null}>Get started</a>
</div>
</div>
</div>
<div className="swiper-slide" data-slide-bg="~/ClientApp/public/images/slider-1-slide-2-1920x671.jpg">
<div className="container">
<div className="swiper-slide-caption">
<h1 data-caption-animate="fadeInUp" data-caption-delay="100">Easy Bets</h1>
<h4 data-caption-animate="fadeInUp" data-caption-delay="200">With the lowest commissions</h4><a className="button button-gray-outline" data-caption-animate="fadeInUp" data-caption-delay="300" href={null}>Join Us</a>
</div>
</div>
</div>
</div>
<div className="swiper-button swiper-button-prev"></div>
<div className="swiper-button swiper-button-next"></div>
<div className="swiper-pagination"></div>
</section>
);
};
}
I am stuck here and I cannot debug further.

Categories

Resources