I am trying to load a pdf file into my project, but I am unable to see it. It just keeps showing 'Loading PDF...'
I have added pdfjs web-worker as mentioned in some of their github repo issues, but still no change. I tried building the page by creating a new project suing create-react-app and it seems to be working fine.
import React, { PureComponent } from "react";
import { Document, Page, pdfjs } from "react-pdf/dist/entry.webpack";
import printJS from "print-js";
import requiredFile from "./pdfdemo.pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${
pdfjs.version
}/pdf.worker.js`;
export default class PdfViewer extends PureComponent {
state = {
numPages: null,
pageNumber: 1,
rotate: 0,
scale: 1
};
onDocumentLoadSuccess = ({ numPages }) => {
console.log('this function was triggered')
this.setState({ numPages });
};
render() {
const { pageNumber, numPages, scale, rotate } = this.state;
return (
<React.Fragment>
<div id="ResumeContainer">
<div style={{ width: 600 }}>
<Document
className="PDFDocument"
file={requiredFile}
onLoadError={(error) => {
console.log("Load error", error)
}}
onSourceSuccess={() => {
console.log("Source success")
}}
onSourceError={(error) => {
console.error("Source error", error)
}}
onLoadSuccess={this.onDocumentLoadSuccess}
>
{window === undefined ? <div>nothing here</div> : <Page
pageNumber={pageNumber}
height={600}
className="PDFPage PDFPageOne"
scale={scale}
/>}
</Document>
</div>
</div>
</React.Fragment>
);
}
}
The onSourceSuccess callback seems to be firing on console logging, but none of the other callbacks fire. In the console, I can see an error stating that the window is undefined.
I managed to resolve my issue. The issue seemed to happen due to a variable assignment to the window object at a completely different place in my application. The funny thing is that there wasn't any issue in the application because of that assignment prior to this.
Hope this info. may help someone else.
change node_modules\react-scripts\config\webpack.config.js
add this line from
output: {
++ globalObject: 'this'
}
https://github.com/wojtekmaj/react-pdf/issues/190
Related
I'm rather new to testing React application, thank you for your time in advance for responding to a newbie question.
So I've been following tutorial on Full Stack Open and came across this challenge about writing tests for React. There is this component Blog which takes some props from App > Blog List > Blog, including one called 'user' which is the returned object from the login function storing username and token etc.
In the Blog's JSX there is a 'remove' button which is shown only to logged in users, controlled by its style determined by a function comparing the username of the original poster of the blog and that of the currently logged in user.
Right now I'm not writing test for username comparison function at all, but it just gets in the way because I can't seem to set a value for 'user' to be passed into the Blog component, and this error was returned during the test:
display: blog.user.username === user.username ? '' : 'none'
^
TypeError: Cannot read properties of undefined (reading 'username')
And here are the codes of the Blog component and the test at current state:
import { useState } from 'react'
const Blog = ({ blog, addLike, deleteBlog, user }) => {
const [showDetails, setShowDetails] = useState(false)
const showWhenDetailsTrue = { display: showDetails ? '' : 'none' }
const toggleDetails = () => {
setShowDetails(!showDetails)
}
const postedBySelf = async () => {
const style = await {
display: blog.user.username === user.username ? '' : 'none',
}
return style
}
return (
<div style={blogStyle}>
<div>
{blog.title} {blog.author}{' '}
<button onClick={toggleDetails}>{showDetails ? 'hide' : 'view'}</button>
</div>
<div style={showWhenDetailsTrue} className="defaultHidden">
<div>{blog.url}</div>
<div>
likes {blog.likes}
<button onClick={() => addLike(blog.id)}>like</button>
</div>
<div>{blog.author}</div>
<button onClick={() => deleteBlog(blog)} style={postedBySelf()}>
remove
</button>
</div>
</div>
)
}
export default Blog
The test file:
import React from 'react'
import '#testing-library/jest-dom/extend-expect'
import { render, screen } from '#testing-library/react'
import Blog from './Blog'
test('renders title and author, but not url or number of likes by default', async () => {
const blog = {
title: 'Blog title',
author: 'Blog author',
url: 'Blog url',
user: {
username: 'mockuser',
},
}
await render(<Blog blog={blog} user={{ username: 'mockuser' }} />)
screen.getByText('Blog title', { exact: false })
screen.getAllByText('Blog author', { exact: false })
const { container } = render(<Blog blog={blog} />)
const div = container.querySelector('.defaultHidden')
expect(div).toHaveStyle('display: none')
})
When the postedBySelf function and associated content are commented out the test is passed. My question is, how can I mock the 'user' object and pass it into the component during the test? I don't understand why it is undefined even if I explicitly declared its value.
Thanks again for your time and appreciate your advice.
Finally spotted my mistake, had to pass in the user in the second rendering of the Blog too.
I wasn't quite sure if I'm missing critical knowledge on this topic but this tutorial explains things very well and helped me spotted the issue in a way. Strongly recommended: https://www.youtube.com/watch?v=OVNjsIto9xM
I've made a netflix clone using React.js, firebase, and have used TMDB api for movie database.
I've also used react-youtube and movie-trailer npm.
So it has this feature that every time I click on any movie poster, it's trailer must be played.
But for most of the movies, trailer doesn't shows up.
This is the error that I face -
movie-trailer: No TMDB Movie found with the current search terms, try searching https://www.themoviedb.org/search?query=Luis%20Miguel%3A%20The%20Series
TypeError: Failed to construct 'URL': Invalid URL
at Row.js:37
'This is the screenshot of errors I am facing on clicking maximum of movies'
I'm sharing the link of my github repo and deployed website as well for reference -
github - https://github.com/IshitaSharma3101/netflix-clone
website - https://netflix-clone-afb8b.web.app/
Row component code-
import React, { useState, useEffect } from "react";
import YouTube from "react-youtube";
import axios from "./axios";
import "./Row.css";
import movieTrailer from "movie-trailer"
const base_url = "https://image.tmdb.org/t/p/original/";
function Row({ title, fetchURL, isLargeRow }) {
const [movies, setMovies] = useState([]);
const [trailerURL, setTrailerURL] = useState("");
useEffect(() => {
async function fetchData() {
const request = await axios.get(fetchURL);
console.log(request.data.results);
setMovies(request.data.results);
return request;
}
fetchData();
}, [fetchURL]);
const opts = {
height: "390",
width: "100%",
playerVars: {
autoplay: 1,
},
};
const handleClick = (movie) => {
if (trailerURL) {
setTrailerURL("");
} else {
movieTrailer(movie?.name || movie?.title || movie?.original_title || "")
.then((url) => {
const urlParams = new URLSearchParams(new URL(url).search);
setTrailerURL(urlParams.get("v"));
})
.catch((error) => console.log(error));
}
};
return (
<div className='row'>
<h2>{title}</h2>
<div className='row__posters'>
{movies.map((movie) => (
<img
key={movie.id}
onClick={() => handleClick(movie)}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`${base_url}${
isLargeRow ? movie.poster_path : movie.backdrop_path
}`}
alt={movie.name}
/>
))}
</div>
{trailerURL && <YouTube videoId={trailerURL} opts={opts} />}
</div>
);
}
export default Row;
I'm sure you are following the Clever Qazi tutorial as I'm doing. I think there is basically no solution for this problem. I also try to get the trailer of the movies by the ID that TMDB gives for every film but this method definitely doesn't work for mine. My conclusion is that movie-trailer is not working for certain kind of film or series...
You can prove yourself my conlclusion by typing on a terminal npx movie-trailer Cobra Kai
which is the command that allow you to use this package. Cobra Kai is a well know series but this "tool" doesn't find any trailer for it.
Use this instead.
movieTrailer(null ,{ tmdbId: movie.id })
.then((url)=>{
console.log("url is "+url);
const urlParams=new URLSearchParams(new URL(url).search);
console.log("urlParamsn"+urlParams);
setTrailerUrl(urlParams.get("v"));
})
.catch((error)=> console.log(error));
}
}
With this you can search for the movie with the tmdb id.
This error is coming becouse TMDB has not added ids for some videos if you want to play all video you just need need to change the genres of the Netflix Original Video from the path in request.js folder where you wrote your path becouse Netflix originals Videos has not linked with ids on TMDB.
The Project
I have a project (React, Typescript, React useContext) that calls an api to fetch information about the episodes of a series, then display the information as cards.
Current status
Last time I ran the project, it worked, I deployed it to Heroku, it worked. One month later, after no changes, it doesn´t work either on my local or on heroku, they throw the same error.
Errors:
Uncaught TypeError: Cannot read property 'medium' of null
at EpisodesList.tsx:21
EpisodesList.tsx:21 Uncaught (in promise) TypeError: Cannot read property 'medium' of null
at EpisodesList.tsx:21
The Episodelists component
const EpisodesList = (props: any): JSX.Element => {
const { episodes, toggleFavAction, favourites, store } = props;
const { state, dispatch } = store;
return episodes.map((episode: Episode) => {
return (
<div key={episode.id} className="episode-box">
<section>
<img
src={episode.image.medium}
/>
<div>{episode.name}</div>
<div>
Season: {episode.season} Number: {episode.number}
</div>
</section>
</div>
);
});
};
export default EpisodesList;
The Home page that uses the component
const Home = () => {
const { state, dispatch } = React.useContext(Store);
useEffect(() => {
state.episodes.length === 0 && fetchDataAction(dispatch);
});
const props: EpisodeProps = {
episodes: state.episodes,
store: { state, dispatch },
toggleFavAction,
favourites: state.favourites,
};
return (
<section className="episode-layout">
{console.log("props in home return is:", props)}
<EpisodesList {...props} />
</section>
);
};
Console log + what I tried
Maybe the issue is related to this --> the console.log in the return part shows:
props in home return is: {episodes: Array(0), store: {…}}
props in home return is: {episodes: Array(42), store: {…}}
The weird thing is, if I remove the image element from the Episodelist component, it works without errors, all the data is there (I can see it in the console.log, even the image.medium).
Any ideas why I am suddenly getting these errors and how I can reinsert my image element?
All you have to do is use conditional rendering for the image.
<img src={episode.image && episode.image.medium} /> or
<img src={episode.image ? episode.image.medium : "some default image"} />
This happens because on initial render the "image" property of "episode" is null and you are trying to access it like that "episode.null.medium" so you need to add a condition that will try to access the "medium" property only when "episode.image" is not null.
I'm getting the following error in my React Component:
Failed to compile.
./src/components/GameInfo.js
Line 13: 'isPlaying' is not defined no-undef
Search for the keywords to learn more about each error.
But I have that state defined in the same file, here's the whole thing:
import React from 'react';
import { Layer, Stage } from 'react-konva';
import { connect } from 'react-redux';
import Banner from './Banner.js';
import CurrentTetromino from '../containers/CurrentTetromino.js';
import ActiveTetrominos from '../containers/ActiveTetrominos.js';
import gameConstants from '../gameConstants.js';
import style from '../styles/styles.css';
const { fieldHeight, fieldWidth } = gameConstants;
let GameField = ({ isPlaying, isPaused, isGameOver }) => {
if (isPlaying) {
return (
<div style={{display: 'inline'}}>
<div className={style.gameField}>
<Stage width={fieldWidth} height={fieldHeight}>
<Layer>
<CurrentTetromino />
<ActiveTetrominos />
</Layer>
</Stage>
{ isPaused ? <Banner label="PAUSED" color="black" opacity=".5" /> : null}
</div>
{ isGameOver ? <Banner label="GAME OVER" color="red" opacity=".8" /> : null}
</div>
);
}
return null;
};
const mapStateToProps = ({ gameStatus }) => ({
isPlaying: gameStatus !== 'IDLE',
isPaused: gameStatus === 'PAUSED',
isGameOver: gameStatus === 'GAME_OVER',
});
GameField = connect(mapStateToProps)(GameField);
export default GameField;
I imagine the error that's causing this will also return similarly for isPaused and isGameOver.
I'm not sure why it's not picked up those consts in mapStateToProps. Unfortunately with React, it really only tells me the line which the error is occurring (line 13).
Any advice would be greatly appreciated.
This dumb site won't let me comment but I would check that gameStatus is going through ok in your mSTP. Instead of doing the implicit return I would change it explicit and console.log the gameStatus in your mSTP. Or slap a debugger in there. That would be my first instinct to check.
const mapStateToProps = ({ gameStatus }) => {
console.log(gameStatus);
return {
isPlaying: gameStatus !== 'IDLE',
....
}
}
If you could share what that brings up I can probably help you out more. otherwise good luck and hopefully that helps figure out the issue.
In classic programming fashion, I had a typo 'IsPLaying' instead of 'IsPlaying'.
Thank you for the help!
Since upgrading to React 16 I get this error message:
warning.js:33 Warning: Expected server HTML to contain a matching <div> in <body>.
What is generally causing this error message and how can it be fixed?
If you use ReactDOM.hydrate to start web application, you will see this warning.
If your application does not use server-side rendering (ssr), please use ReactDOM.render to start.
If you're using Server Side Rendering like NextJS, delete recent code and compare if you've tried to access a variable directly inside of Component scope where DOM is not guaranteed yet. For me, it was:
import { i18n } from 'i18n'
export default function SomeComponent() {
const initLanguage = i18n.language <---- causing error
return ...
}
If you need to access such properties, access it within useEffect, so as to make sure that document is already established by then. It is kinda equivalent to componentDidMount():
import { i18n } from 'i18n'
import { useEffect, useState } from 'react'
export default function SomeComponent() {
const [initlanguage, setInitLanguage] = useState('en')
useEffect(() => setInitLanguage(i18n.language), [])
return ...
}
If your HTML code is like
<table>
<tr>
you can get this error.
To get around it, use the <tbody> tag like
<table>
<tbody>
<tr>
Don't forget to close the tag(s)!
This seems to be because of Browsersync inserting a script tag in the body on client side that does not exist on server side. Thus React fails to attach to the server render.
I got this using material UI by trying to do const searchParams = new URLSearchParams(process.browser ? window.location.search : '') at the top of the react component in my NextJS app with material-ui SnackBar, I was able to remove the error by putting this in a useEffect hook.
Entire component for reference:
export default function SnackBarMessage() {
const [requestLogin, setRequestLogin] = useState(false)
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return
}
setRequestLogin(false)
}
useEffect(() => {
// had to move into a useEffect hook
const searchParams = new URLSearchParams(process.browser ? window.location.search : '')
const hasRequestLogin = Boolean(searchParams.get('requestLogin'))
if (hasRequestLogin) {
setRequestLogin(true)
}
}, [])
return (
<>
{requestLogin && (
<Snackbar open={requestLogin} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity='error' style={{ fontSize: '18px' }} elevation={6}>
Please Log Back In
</Alert>
</Snackbar>
)}
</>
)
}
In my case it was because of using PersistGate and react-loadable.
if you using this libraries, you could use preloadAll instead of preloadReady
In my case i installed REACTFUL and it do a render so different by default install:
src/renderers/dom.js
ReactDOM.hydrate(
<App initialData={window.__R_DATA.initialData} />,
document.getElementById('root'),
);
src/renderers/server.js
const initialData = {
appName: 'Reactful',
};
return Promise.resolve({
initialData,
initialMarkup: ReactDOMServer.renderToString(
<App initialData={initialData} />,
),
pageData,
});
care with initialData!
i fix it changed dom.js like it, attention to initialData is important:
const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate;
const initialData = {
appName: 'Reactful',
};
renderMethod(
<App initialData={initialData} />,
document.getElementById('root'),
);
The issue can be caused because the client and server mismatch during HMR updates
I resolved that way:
const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate
const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate
renderMethod(
<AppContainer>
<Comp />
</AppContainer>,
document.getElementById('root')
)
In my case I got an error when upgrading to Next.js 13, specifically when using Drawer from #mui/material. It seems switching to server side components is not easy.
return (
<Drawer
anchor="left"
onClose={onClose}
open={open}
PaperProps={{
sx: {
backgroundColor: 'neutral.900',
color: '#FFFFFF',
width: 280
}
}}
sx={{zIndex: (theme) => theme.zIndex.appBar + 100}}
// 'persistent' or 'permanent' throws error
variant="temporary"
>
{content}
</Drawer>
);
Looks like you're trying to access a prop in a dom before is ready. You can use a structure like this:
{(variable) && sameVariable}
I'm assuming you are using ssr. The warning is about attempting to render before there is a window object. You need to hydrate.
ReactDOM.hydrate(<App />, document.getElementById("home"))
What I don't understand, is that the App component is being served static by express. Why is it trying to render before it is served? Bring on the comments.