I'm trying to copy a text to clipboard using a button, the code working fine but the problem is copying another post text not the targeted one! I have multi posts using map. and each post has a text and a button, the issue now is when i'm hitting the button it copies the first post text!
The code for Post.jsx
export default function Post({ post }) {
var cpnBtn = document.getElementById("cpnBtn");
var cpnCode = document.getElementById("cpnCode");
const CopyCode = () => {
navigator.clipboard.writeText(cpnCode.innerHTML);
cpnBtn.innerHTML = "COPIED";
setTimeout(function(){
cpnBtn.innerHTML = "COPY CODE";
}, 3000);
}
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span >{post.shop}</span>
</div>
<div className="postTitle">
<span >{post.title}</span>
</div>
<div className="coupon-row">
<span id="cpnCode">{post.coupon}</span>
<button id="cpnBtn" onClick={CopyCode}>COPY CODE</button>
</div>
</div>
</div>
</div>
</div>
);
}
The code for Posts.jsx
export default function Posts({ posts }) {
return (
<div className="posts">
{posts.map((p) => (
<Post post={p} />
))}
</div>
);
}
The reason why it's copying always the first coupon is that you're rendering multiple posts and all have a coupon with id="cpnCode" so it will always use the top one. Besides that, I've explained below the proper way to implement such functionality in react.
The easiest way to solve this would be to use the useState of react to hold the text of the button in it. When using react we try to avoid mutating DOM elements manually instead we rely on to react to perform these updates.
Also, there's no need to take the coupon value from the coupon HTML element if you already have access to the post.
writeText is a Promise that's why I added the then block and the catch so you can see the error in your console in case something goes wrong.
import { useState } from "react";
export default function Post({ post }) {
const [bttnText, setBttnText] = useState("COPY CODE");
const copyCode = () => {
navigator.clipboard
.writeText(post.coupon)
.then(() => {
setBttnText("COPIED");
setTimeout(function () {
setBttnText("COPY CODE");
}, 3000);
})
.catch((err) => {
console.log(err.message);
});
};
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span>{post.shop}</span>
</div>
<div className="postTitle">
<span>{post.title}</span>
</div>
<div className="coupon-row">
<span>{post.coupon}</span>
<button onClick={copyCode}>{bttnText}</button>
</div>
</div>
</div>
</div>
</div>
);
}
Alterantively in case you really need to access the htmlElements it can be done with useRef e.g
import { useState, useRef } from "react";
export default function Post({ post }) {
const [bttnText, setBttnText] = useState("COPY CODE");
const couponRef = useRef();
const copyCode = () => {
// just a safety mechanism to make sure that
// the references found the DOM elmenets button and coupon
// before trying to use them
if (!couponRef.current) return;
navigator.clipboard
// again doesn't make sense to use here
// couponRef.current.innerHTML
// since you got access to post.coupon
.writeText(couponRef.current.innerHTML)
.then(() => {
setBttnText("COPIED");
setTimeout(function () {
setBttnText("COPY CODE");
}, 3000);
})
.catch((err) => {
console.log(err.message);
});
};
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span>{post.shop}</span>
</div>
<div className="postTitle">
<span>{post.title}</span>
</div>
<div className="coupon-row">
<span ref={couponRef}>{post.coupon}</span>
<button onClick={copyCode}>{bttnText}</button>
</div>
</div>
</div>
</div>
</div>
);
}
Related
I want to call api and generate div using data from api, but I don't know why this code is not working. It doesn't show anything on the page.
This is my code. countryArray is an object array, and it has property of population, name, continent, capital.
import React from 'react'
function Countries() {
fetch("https://restcountries.com/v3.1/all")
.then((response)=>response.json())
.then((countryArray)=>{
return (
<div>
{countryArray.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
},
(err)=>{
console.log(err);
})
}
export default Countries
Hello there first of all you need save the api data in a state and then fetch the api in useEffect then you can use the api data in your react app
import React , {useState , useEffect} from 'react';
function app() {
const [examples , setExamples] = useState([]);
useEffect(() => {
fetch('https://restcountries.com/v3.1/all')
.then((res) => res.json())
.then((data) => {
setExamples(data);
})
.catch((err) => console.log(err));
},[]);
return(
<>
<div>
{
examples.map((example) => (
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{example.name.official}</h2>
<p>Population: {example.population}</p>
<p>Region: {example.continents}</p>
<p>Capital: {example.capital}</p>
</div>
</div>
))
}
</div>
</>
);
}
export default app
this code is working
You need to return a jsx element. The usual way of doing data fetching inside react component is to do it inside an effect.
A minimal example would be like this.
function Countries() {
const [countryArray, setCountryArray] = useState([]);
useEffect(() => {
(async function () {
const res = await fetch("https://restcountries.com/v3.1/all");
const json = await res.json();
setCountryArray(json)
})()
}, [])
return (
<div>
{countryArray.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name.common}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
}
Ofc you should also take care of race conditions, errors, loading states, or use a library that does all this stuff for you and more like react query.
Check the documentation for more information, fetching data
You can't return jsx from fetch, that won't be rendered.
Use useState inside a useEffect to save the data, then return from the functinon itself
const {useState, useEffect} = React;
function Countries() {
const [ data, setData ] = useState([])
useEffect(() => {
function getData() {
fetch("https://restcountries.com/v3.1/all")
.then((response) => response.json())
.then((countryArray) => setData(countryArray)
);
};
getData();
}, [ ]);
return (
<div>
{data.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name.common}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
}
ReactDOM.render(<Countries />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Demo takes quite some time to load, so here's a pic:
I'm using firestore database to store my data in the collection "listings". So for each document in "listings", I need to render a <BookListing/> element in Home.js with the data from each document. From my research, there are a few other questions similar to this one out there, but they're outdated and use different react syntax. Here's my code:
function BookListing({id, ISBN, title, image, price}) {
return (
<div className="bookListing">
<div className='bookListing_info'>
<p className="bookListing_infoTitle">{title}</p>
<p className="bookListing_infoISBN"><span className="bookListing_infoISBNtag">ISBN: </span>{ISBN}</p>
<p className="bookListing_infoPrice">
<small>$</small>
{price}
</p>
</div>
<img className="bookListing_img" src={image} alt=""></img>
<button className="bookListing_addToCart">Add to Cart</button>
</div>
)
}
export default BookListing
function Home() {
document.title ="Home";
useEffect(() => {
getDocs(collection(db, 'listings'))
.then(queryCollection => {
queryCollection.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
const element = <BookListing id="456" ISBN="0101" title="sample_title" image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg" price="25"/>;
ReactDOM.render(
element,
document.getElementById('home-contents-main')
);
})
});
}, []);
return (
<div className="home">
<div className="home_container">
<div id="home-contents-main" className="home_contents">
</div>
</div>
</div>
)
}
export default Home
It's best (and most common) to separate the task into two: asynchronously fetching data (in your case from firestore), and mapping that data to React components which are to be displayed on the screen.
An example:
function Home() {
// A list of objects, each with `id` and `data` fields.
const [listings, setListings] = useState([]) // [] is the initial data.
// 1. Fetching the data
useEffect(() => {
getDocs(collection(db, 'listings'))
.then(queryCollection => {
const docs = [];
queryCollection.forEach((doc) => {
docs.push({
id: doc.id,
data: doc.data()
});
// Update the listings with the new data; this triggers a re-render
setListings(docs);
});
});
}, []);
// 2. Rendering the data
return (
<div className="home">
<div className="home_container">
<div className="home_contents">
{
listings.map(listing => (
<BookListing
id={listing.id}
ISBN={listing.data.ISBN}
title={listing.data.title}
image={listing.data.image}
price={listing.data.price}
/>
))
}
</div>
</div>
</div>
);
}
Some tips:
Fetching data from other web servers or services can be, and typically is, done in the same manner.
This example could be improved a lot in terms of elegance with modern JS syntax, I was trying to keep it simple.
In most cases, you don't want to use ReactDOM directly (only for the entry point of your app), or mess with the DOM manually; React handles this for you!
If you're not familiar with the useState hook, read Using the State Hook on React's documentation. It's important!
You can create a reusable component, and pass the data to it, and iterate over it using map() . define a state, and use it within the useEffect instead of creating elements and handling the process with the state as a data prop.
function BookListing({ id, ISBN, title, image, price }) {
return (
<div className="bookListing">
<div className="bookListing_info">
<p className="bookListing_infoTitle">{title}</p>
<p className="bookListing_infoISBN">
<span className="bookListing_infoISBNtag">ISBN: </span>
{ISBN}
</p>
<p className="bookListing_infoPrice">
<small>$</small>
{price}
</p>
</div>
<img className="bookListing_img" src={image} alt=""></img>
<button className="bookListing_addToCart">Add to Cart</button>
</div>
);
}
function Home() {
const [data, setData] = useState([]);
useEffect(() => {
document.title = 'College Reseller';
getDocs(collection(db, 'listings')).then((queryCollection) => setData(queryCollection));
}, []);
return (
<div className="home">
<div className="home_container">
<div id="home-contents-main" className="home_contents">
{data.map((doc) => (
<BookListing
id="456"
ISBN="0101"
title="sample_title"
image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg"
price="25"
/>
))}
</div>
</div>
</div>
);
}
export default Home;
I am using json-server and fetching data using fetch. First time I get data properly in an Owl Carousel and the slider works fine but after when I refresh the page all my dynamic data wipe out. Still my carousel slides but with no data. Also I have attached a jquery script https://code.jquery.com/jquery-3.2.1.slim.min.js in index.html.
I am loosing my Owl Carousel Dynamic Data which I am using through map method in the Owl Carousel Component. Below is the code where I am using my slider. Please help me to find where I am doing wrong. Thank You.
---------------
<<<<<- Below code is MainSlider.js ->>>>>
import React, { useReducer, useEffect } from "react";
import OwlCarousel from "react-owl-carousel";
import "owl.carousel/dist/assets/owl.carousel.css";
import { mainSliderReducer } from "../reducers/mainSliderReducer";
const API = "http://localhost:8000/mainSlider";
const initialState = {};
const MainSlider = () => {
const [state, dispatch] = useReducer(mainSliderReducer, initialState);
const { data } = state;
useEffect(() => {
getData();
}, []);
const getData = () => {
fetch(API)
.then((res) => {
if (res.ok) {
return res.json();
} else {
console.log("DATA NOT FOUND. SOME ERROR");
throw new Error("ERROR FETCHING DATA");
}
})
.then((data) => dispatch({ type: "GET_MAINSLIDER_DATA", payload: data }))
.catch((err) => console.log(err));
};
console.log(data);
return (
<>
<OwlCarousel className="owl-theme" loop margin={10} nav>
{data ? (
data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})
) : (
<h1>"SLIDE NOT FOUND"</h1>
)}
</OwlCarousel>
</>
);
};
export default MainSlider;
<<<<<- Below code is mainSliderReducer.js ->>>>>
export const mainSliderReducer = (state, action) => {
console.log(state, action);
switch (action.type) {
case "GET_MAINSLIDER_DATA":
return { ...state, data: action.payload };
default:
return state;
}
};
Hey I found my own question's answer and i found the way which i am sharing to you all. Just check if data is available then only you load the Owl Carousel Component. Check the code below for better understanding.
{data && (
<OwlCarousel {...options}>
{data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})}
</OwlCarousel>
)}
i'm having a problem displaying the data from the punkbeer API and would appreciate any kind of help
import { useEffect, useState, Fragment } from 'react';
import { Switch, Link, Route, BrowserRouter as Router } from 'react-router-dom';
import React from 'react'
import '../Drink/drinks.css';
function Drinks() {
const [beer, setBeer] = useState('[]');
const [selectedBeer, setSelectedBeer] = useState("")
const fetchDrinks = function() {
fetch(`https://api.punkapi.com/v2/beers`)
.then( function(result) {
return result.json()
})
.then(function (data) {
setBeer(data)
data.forEach(beer => {
<div>
<div className="drink-img">
<img src="{beer.image_url}"/>
</div>
<div className="drink-title">
<h2>{beer.name}</h2> </div>
<div className="drink-tagline">
<h2>{beer.tagline}</h2> </div>
<div className="drink-food">
<h2>{beer.food_pairing}</h2> </div>
</div>
});
})
.catch(function () {
});
}
useEffect( function(){
fetchDrinks();
}, []);
return (
<div className="drink-container">
<div className="next">
<p>After you are picked your drink, click next to place your order </p>
<Link to="./Order">
<button className="btn" >Order</button>
</Link>
</div>
</div>
)
}
export default Drinks
You can save the return in variable/state.
Example you save in variabe that have name "data"
in view, you can add this
{data.map((value,index)=>{
return(
<div key={index}>
<div className="drink-img">
<img src="{value.image_url}"/>
</div>
<div className="drink-title">
<h2>{value.name}</h2> </div>
<div className="drink-tagline">
<h2>{value.tagline}</h2> </div>
<div className="drink-food">
<h2>{value.food_pairing}</h2> </div>
</div>
)}
)}
I've read all the question asked that similar to my problem , but it still cant's solve my issues . I'm fetching datas from an api and assign it's values into my state , the program compiled successfully but this message appears in the browser "TypeError: weatherData.main is undefined"
Here's my code
import './App.css';
import React,{useEffect,useState} from 'react';
function App() {
const [weatherData,setWeatherData] = useState({});
const [position,setPosistion] = useState({});
useEffect(()=>{
navigator.geolocation.getCurrentPosition( pos => {
setPosistion(()=>{
return {
latitude : pos.coords.latitude,
longitude : pos.coords.longitude
}
})
});
},[])
useEffect(()=>{
fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&units=metric&appid=a*****5`)
.then( res => res.json() )
.then( resJson => {
setWeatherData(()=>resJson)
})
},[position]);
return (
<div className="App">
<Weather weatherData={weatherData} />
</div>
);
}
const Weather = ({weatherData}) => {
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}
export default App;
the state contains
{"coord":{"lon":106.8451,"lat":-6.2146},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":302.76,"feels_like":307.06,"temp_min":300.15,"temp_max":305.93,"pressure":1007,"humidity":74},"visibility":6000,"wind":{"speed":2.57,"deg":340},"clouds":{"all":40},"dt":1613038370,"sys":{"type":1,"id":9383,"country":"ID","sunrise":1612997835,"sunset":1613042198},"timezone":25200,"id":1642911,"name":"Jakarta","cod":200}
Before the data is fetched, weather is initialised to be a empty object and hence weather.main is undefined.
You should consider rendering a fallback page till weather data is fetched
const Weather = ({weatherData}) => {
if(Object.keys(weatherData).length === 0) {
return <div>{/* Somee info here or maybe a loader*/}</div>
}
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}