I have a simple nextjs page which has only one div with simple h1 Tag and React video player component. I want to take a screenshot of my view of h1 tag and video player whatever is playing in that moment using puppeteer. I have implemented puppeteer but it does not take the screenshot of video player instead it returns only h1 tag and blank afterwards.
Actual image I want:
Puppeteer screenshot:
I am using nextjs client side api folder to call puppeteer.
Node js code:
import puppeteer from "puppeteer";
export default async function My(req, res) {
const url = req.query.url;
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url);
const img = await page.screenshot({ path: "output.png" });
console.log("img", img);
await page.close();
await browser.close();
return res.json("done");
}
My component:
import styles from "../styles/Home.module.css";
import React, { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";
const Player = dynamic(() => import("../components/player"), {
ssr: false,
});
export default function Home() {
useEffect(() => {
if (typeof window === undefined) {
return;
}
const url = "http://localhost:3000";
setTimeout(() => {
fetch(`http://localhost:3000/api/scrapper?url=${url}`)
.then((res) => {
res.json();
})
.then((data) => {
console.log(data);
});
}, 10000);
}, []);
return (
<>
<div
crossOrigin="true"
id="capture"
style={{ display: "block" }}
>
<h3>Hello</h3>
<Player />
</div>
<div style={{ marginTop: "100px" }} id="placement"></div>
</>
);
}
I solved it. Just added waitUntil Parameter in goto method. Actually the reason was puppeteer was taking screenshot before the player could initialize itself in the dom. That's why picture was blank. networkidle0 waits until the component is functional.
await page.goto(url, { waitUntil: "networkidle0" });
Related
I have a nextjs page which consists of a react video player which plays a YouTube video based on some id passed in the url. The YouTube video is fetched in getServerSideProps based on the id. Then on the client side I am using /api/some-route to take a screenshot of that video player div using Puppeteer. Problem is when in api side I am opening a browser with Puppeteer with that particular URL, getServerSideProps is called and again my api/some-routes is getting called. So It has made a loop and is not finishing. How do I stop this?
My page:
export default function Home() {
useEffect(() => {
if (typeof window === undefined) {
return;
}
const url = window.location.href;
setTimeout(() => {
fetch(`/api/scrapper?url=${url}`)
.then((res) => {
res.json();
})
.then((data) => {
console.log(data);
});
}, 10000);
}, [params.slug[0]);
return (
<>
<Layout>
<Frame id="capture" />
</Layout>
</>
);
}
export const getServerSideProps = async ({ params }) => {
return {
props: { params, serverData },
};
}
/api/scrapper.js
import puppeteer from "puppeteer";
export default async function My(req, res) {
const url = req.query.url;
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url);
const img = await page.screenshot({ path: "output.png" });
console.log("img", img);
await page.close();
await browser.close();
return res.json("done");
}
I am using React in front-end and Node and MongoDB in Back-end. I have created a custom hook from where I am loading the data. The following is the custom hook
import { useEffect, useState } from "react";
const useItems = (id) => {
const [item, setItem] = useState([]);
useEffect(() => {
fetch(`http://localhost:5000/inventory/${id}`)
.then((res) => res.json())
.then((data) => setItem(data));
}, [id]);
return [item];
};
export default useItems;
And this is the component where I am calling the custom hook to load the data.
import React, { useEffect, useState } from "react";
import "./Inventory.css";
import { useParams } from "react-router-dom";
import useItems from "../../hooks/useItems";
const Inventory = () => {
const { id } = useParams();
const [item] = useItems(id);
const quantityDecrease = (newQuantity) => {
let quantity = parseInt(newQuantity) - 1;
const updateQuantity = { quantity };
const url = `http://localhost:5000/inventory/${id}`;
fetch(url, {
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(updateQuantity),
})
.then((res) => res.json())
.then((data) => {
console.log("success", data);
alert("saved");
});
};
return (
<div>
<div className="col-lg-6">
<p className="inventory-textbox">
<strong>Quantity :</strong> {item.quantity}
</p>
</div>
<button onClick={() => quantityDecrease(item.quantity)}>
Delivered
</button>
</div>
);
};
export default Inventory;
Whenever the Delivered button is clicked the quantityDecrease function is executed and the quantity of the item is decreased by one. Now, my database is working fine. I am being able to update both client and server site but I have to reload the page in order to see the change in the ui. Is there a way I do not have to reload to see the change?
try using the item data as useEffect dependency. it may solve your problem.
On this case I am trying to show the "_id".
I made the code based on this video.
But by just looking at his API I can see that his data is little different, how can I adapt it to work with my API
import "./App.css";
import axios from "axios";
import { useEffect, useState } from "react";
const App = () => {
const [leitura, setLeitura] = useState([]);
const getLeituraData = async () => {
try {
const data = await axios.get(
"https://estufaarduino.herokuapp.com/sistema/leituras"
);
console.log(data.data);
setLeitura(data.data);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getLeituraData();
}, []);
return (
<div className="App">
{leitura.map((item) => {
return <p>{item._id}</p>;
})}
</div>
);
};
export default App;
I am trying to create a stripe checkout project but was stuck when I found that the loadStripe promise was not working fine and I have to change the code window.stripe but this is also not working .
Her is my react code :
import React, { useEffect, useRef } from "react";
import { isAuth } from "../helpers/auth";
import { useNavigate } from "react-router-dom";
import styles from "./Pricing.module.scss";
import ScriptTag from "react-script-tag";
const Stripe = require('stripe')
const stripe = window.Stripe('pk_8734579834958')
export const Pricing = () => {
const buttonValue = useRef();
const navigate = useNavigate();
const setBtnValue = (e) => {
buttonValue.current = e.target.value;
};
const checkoutHandler = async (e) => {
const btnValue = buttonValue.current;
console.log(btnValue);
fetch("http://localhost:5000/api/checkout", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
btnValue,
}),
})
.then((result) => result.json())
.then(({ sessionID }) => stripe.redirectToCheckout({ sessionID }))
.then((result) => {
console.log(result.error.message);
});
};
return (
<div>
<ScriptTag
isHydrating={true}
type="text/javascript"
src="https://js.stripe.com/v3/"
/>
<form onSubmit = {checkoutHandler}>
<button
value= 'price_bdsahfbadshb'
type="submit"
className="btn"
name="product"
onClick={setBtnValue}
>
Upgrade Now
</button>
</div>
)
}
Here is my backend code :
router.post('/checkout' , async(req,res) => {
const product = req.body;
console.log(product);
}
As you want to redirect, just try adding <script src="https://js.stripe.com/v3/"></script> into index.html (if not added) so you will able to use window.Stripe.
and remove line const Stripe = require('stripe')
if you want more clarification, go through its official documentation.
Question number 1: I've created a CRUD (CMS) app with react where you create articles. My backend is in node.js and my DB is in MySQL. I also have a react-native app that pulls all the articles I created on my CMS. Where do I store the images I add to my articles? In a folder in my backend? Or somewhere else?
Question number 2: So I've connected to my db and I'm displaying on my CMS react web page the title, content and image. And yet when it comes to the image, you can only see the path ie. (C:\fakepath\Screenshot 2020-06-14 at 23.07.52.png), not the actual image. I don't know if the issue is with my backend but after a bit of online research a lot of people said that you need to add require in the src if you want the actual image displayed and not just the path, a bit like this:
<img src={require('./logo.jpeg')} />
However with the way I've done it I don't see how I can use the img tag and add src because I'm fetching image to render from the backend and hence, not creating the img tag. Hope this makes sense.
ViewAllArticles.js
class ViewAllArticles extends Component {
state = {
articles: []
}
getArticles = _ => {
fetch('http://localhost:4000/articles')
.then(response => response.json())
.then(response => this.setState({ articles: response.data }))
.catch(err => console.error(err))
}
componentDidMount() {
this.getArticles();
}
renderArticle = ({ id, title, image }) => <div key={id}>{title}, {image}</div>
render() {
const { articles } = this.state;
return (
<div>
<h1>Home</h1>
<div>
{articles.map(this.renderArticle)}
</div>
</div>
);
}
}
export default ViewAllArticles;
If the require is not what's missing do you have any other ideas of why this is happening?
I'm also pulling the same data for my react-native app and the images don't come up.
This is the code in my react-native app:
largeTitle={item.title} works fine and displays all the titles on the cards but source={item.image} doesn't display the images on the same cards.
HomeFeed.js
import React, { Component } from "react";
import { StyleSheet, Text, View, FlatList } from 'react-native';
import {AppleCard, AppOfTheDayCard} from 'react-native-apple-card-views';
export default class HomeFeed extends Component {
constructor() {
super()
this.state = {
dataSource: []
}
}
// https://github.com/WrathChaos/react-native-apple-card-views
renderItem = ({ item }) => {
return (
<View>
<View style={styles.card}>
<AppleCard
largeTitle={item.title}
footnoteText="subtitle placeholder"
source={item.image}
>
</AppleCard>
</View>
</View>
)
}
componentDidMount() {
const url = 'http://localhost:4000/articles'
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource: responseJson.data
})
})
}
render() {
return(
<View style={styles.homeFeed}>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
/>
</View>
);
}
}
const styles = StyleSheet.create({
homeFeed: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
card: {
padding: 15
}
});
This is my backend code in node.js
index.js
const express = require('express');
const cors = require('cors');
const mysql = require('mysql');
const { query } = require('express');
const multer = require('multer');
const upload = multer({dest: 'public/images'}); // uploaded article image here
const app = express();
//all queries go here
const SELECT_ALL_ARTICLES_QUERY = 'SELECT * FROM articles';
//create connection
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'DidiLydiBibi96',
database: 'myTherapy'
});
connection.connect(err => {
if(err) {
return err;
}
});
//end of creating connection
app.use(cors());
app.get('/', (req, res) => {
res.send('go to /articles to see articles')
});
//ROUTES
//Add new article
app.use('/image', express.static('public/images'));
app.get('/articles/add', upload.single('image'), (req, res) => {
const { title, content, image } = req.query; //fields from db
const INSERT_ARTICLES_QUERY = `INSERT INTO articles (title, content, image) VALUES(?, ?, ?)`;
connection.query(INSERT_ARTICLES_QUERY, [title, content, image], (err, results) => {
if(err) {
return res.send(err)
}
else {
return res.send('successfully added article')
}
});
});
//View all articles
app.get('/articles', (req, res) => {
connection.query(SELECT_ALL_ARTICLES_QUERY, (err, results) => {
if(err) {
return res.send(err)
}
else {
return res.json({
data: results
})
}
});
});
app.listen(4000, () => {
console.log('Articles server listening on port 4000')
});
For the first problem, getting the image uri from the server is good enough, and it's your react application that should handle converting that to a visible image.
One way to do this would be to change your renderArticles method like :
renderArticle = ({ id, title, image }) => (
<div key={id}>
{title}
<div
style={{
width: "100px",
height: "100px",
backgroundSize: "cover",
backgroundImage: "url(" + image + ")"
}}
></div>
</div>
);