I'm trying to build a simple youtube app using youtube-api-search. There's two main portion of the app ie. VideoDetail & VideoList. VideoDetail is intended to show/play the video whereas VideoList is for displaying a list of five videos with their titles.
Now, the issue is, top section of my app ie. is getting re-rendered continuously inside a loop. I cant figure out why that is. I app is really simple it doesn't even have any lifecycle methods. Please help me to figure out the error.
App.js (It is imported into index.js where it gets rendered)
import React, { Component } from 'react';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
const API_KEY = 'AIzaSyC----key------N7khtCs';
class App extends Component {
constructor(props){
super(props);
this.state = {
videos: [],
selectedVideo: null
};
console.log('sth.');
YTSearch({key: API_KEY, term: 'surfboards'}, (videos) => {
this.setState({
videos: videos,
selectedVideo: videos[0]
});
});
}
render(){
return (
<div>
{console.log('indexx')}
<VideoDetail video={this.state.selectedVideo} />
<VideoList
onVideoSelect={selectedVideo => this.setState({selectedVideo})}
videos={this.state.videos}
/>
</div>
);
};
}
export default App;
video_detail.js
import React from 'react';
const VideoDetail = ({video}) => { //accesssing props elements direcly
if(!video){
return <div>Loading Details</div>;
}
const videoId = video.id.videoId;
const url = `https//www.youtube.com/embed/${videoId}`;
return (
<div className="video-detail col-md-8">
<div className="embed-responsive embed-responsive-16by9">
<iframe className="embed-responsive-item" src={url}></iframe>
</div>
<div className="details">
<div>{video.snippet.title}</div>
<div>{video.snippet.description}</div>
</div>
</div>
);
};
export default VideoDetail;
video_list.js
import React from 'react';
import VideoListItem from './video_list_item';
const VideoList = props => {
const videoItems = props.videos.map((video) => {
console.log(video);
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video={video} />
);
});
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
);
};
export default VideoList;
video_list_item.js
import React from 'react';
const VideoListItem = ({video, onVideoSelect}) => { //pulling from props
const imageUrl = video.snippet.thumbnails.default.url;
return(
<li onClick={() => onVideoSelect(video)} className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} />
</div>
<div className="media-body">
<div className="media-heading">{video.snippet.title}</div>
</div>
</div>
</li>
);
}
export default VideoListItem;
Someone, please explain me what is the issue here. I want to understand.
Finally figured out the issue:
I was because : was not present in the url.
const url = https://www.youtube.com/embed/${videoId};
Related
I'm very new to react and don't understand quite all of the restrictions yet. I'm trying to do a simple page switch after a button is clicked. After researching I figured useNavigate() would be used best for this situation. After trying to implement it into my code I realized what I had, did absolutely nothing. My goal is to send the user to a home page once the register button is clicked. As of right now, when I click the button nothing happens. This could be some small detail I missed or just me being completely oblivious. Please let me know if you think you see anything of importance, thanks in advance.
Here is my apps main page with my path being src/components/login/register:
import React from "react";
import "react-datepicker/dist/react-datepicker.css";
import { useNavigate } from "react-router-dom";
import axios from 'axios';
const api = axios.create({
...
})
const sendDetailsToServer = (payload) => {
...
}
const GoToLogin = () => {
let navigate = useNavigate();
navigate('/home');
}
export class Register extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onInputchange = this.onInputchange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
onInputchange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
onSubmitForm() {
let registerInfo = {
user_name : this.state.username,
password : this.state.password,
email_id : this.state.email
}
sendDetailsToServer(registerInfo);
GoToLogin();
}
render() {
return (
<div className="base-container" ref={this.props.containerRef}>
<h1>Welcome!</h1>
<link rel="stylesheet" href="" />
<div className="header">Please Enter Your Account Information</div>
<div className="content">
...
<div className="footer">
<button type="button" className="btn" onClick={this.onSubmitForm}>
Register
</button>
</div>
<div className="footer-fill"></div>
</div>
);
}
}
Here is my home page found under my path src/components/login/home:
import React from "react";
const Home = () => {
return(
<div>
<h1>Login</h1>
</div>
);
};
export default Home;
useNavigate hook is added to version 6, and it can be used only in functional component. If you want to use it in class component, create a HOC(withRouter).
import { useNavigate } from "react-router-dom";
export const withRouter = (Component) => {
const Wrapper = (props) => {
const navigate = useNavigate();
return <Component navigate={navigate} {...props} />;
};
return Wrapper;
};
and use it in your register.js like this
export default withRouter(Register)
here is the complete code.
import React from "react";
import "react-datepicker/dist/react-datepicker.css";
import axios from 'axios';
const api = axios.create({
...
})
const sendDetailsToServer = (payload) => {
...
}
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onInputchange = this.onInputchange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
onInputchange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
onSubmitForm() {
let registerInfo = {
user_name : this.state.username,
password : this.state.password,
email_id : this.state.email
}
sendDetailsToServer(registerInfo);
this.props.navigate('/home');
}
render() {
return (
<div className="base-container" ref={this.props.containerRef}>
<h1>Welcome!</h1>
<link rel="stylesheet" href="" />
<div className="header">Please Enter Your Account Information</div>
<div className="content">
...
<div className="footer">
<button type="button" className="btn" onClick={this.onSubmitForm}>
Register
</button>
</div>
<div className="footer-fill"></div>
</div>
);
}
}
export default withRouter(Register)
sample code
I want to implement the navigation on menu bar which I am fetching from api. For e.g. on home page I have four menus like menu1 menu2 menu3 menu4 which displays always. On click on these menus i want to fetch products related to them.
I have read about nested routes in React js but unable to implement that.
Dynamic menu bar of categories:
import React from 'react';
import './style.css';
import {Link} from 'react-router-dom';
import Api from '../../Api';
class TopMenu extends React.Component {
state = {
categories : []
}
componentDidMount(){
Api.get(`categories`).then(
response => {
this.setState({categories: response.data});
});
};
render(){
return (
<div className="menu">
{this.state.categories.map(category => (
<Link to={"/category/" + category.name} key={category.id} className="menu-item"><span>{category.name}</span></Link>
))}
</div>
);
}
};
export default TopMenu;
My Routes file:
import React from 'react';
import {Switch, Route} from 'react-router-dom';
import CategoryProducts from './CategoryProducts';
import Home from './Home';
const Routes = () => {
return(
<Switch>
<Route path='/' exact component={Home} />
<Route path='/category/:name' component={CategoryProducts} />
</Switch>
);
};
export default Routes;
The click on Category will just change the browser url, not the page.
CategoryProducts.ja
import React from 'react';
import Products from './Products';
class CategoryProducts extends React.Component {
render(){
return (
<div className="content-wrapper">
<div className="menu-left">
<Products/>
</div>
</div>
);
}
}
export default CategoryProducts;
Products.js
import React,{useState, useEffect} from 'react';
import Api from './Api'
import Card from './components/Card';
class Products extends React.Component {
state = {
categories : []
}
componentDidMount(){
let categoryName = this.props.match ? this.props.match.params.name : 'Veg Pizza';
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
};
render(){
return (
<div>
<div className="ref">
<div className="menu-hr"></div>
<div className="menu-cat">
<div className="menu-catname ">BESTSELLERS</div>
</div>
</div>
<div className="card-container">
<div className="all-cards" data-label="Bestsellers">
<Card />
</div>
</div>
</div>
);
}
};
export default Products;
Your Products component is not mounting again and again, because this renders on all possible categories. Therefore In order to fetch data for different categories, you might have to use componentDidUpdate lifecycle method.
import React,{useState, useEffect} from 'react';
import Api from './Api'
import Card from './components/Card';
class Products extends React.Component {
state = {
categories : []
}
componentDidMount(){
let categoryName = this.props.match ? this.props.match.params.name : 'Veg Pizza';
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
};
componentDidUpdate(prevProps, prevState){
if(prevProps.match.params.name !== this.props.match.params.name){
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
}
}
render(){
return (
<div>
<div className="ref">
<div className="menu-hr"></div>
<div className="menu-cat">
<div className="menu-catname ">BESTSELLERS</div>
</div>
</div>
<div className="card-container">
<div className="all-cards" data-label="Bestsellers">
<Card />
</div>
</div>
</div>
);
}
};
export default Products;
If you want to force rerenders anyway and componentDidUpdate doesnt works for you, you can cause force rerender using key prop
import React from 'react';
import Products from './Products';
class CategoryProducts extends React.Component {
render(){
return (
<div className="content-wrapper">
<div className="menu-left">
<Products key={this.props.match.params.name}/>
</div>
</div>
);
}
}
export default CategoryProducts;
Please let me know if ut didnt solve your problem.
I have been trying to use React-paginate library for pagination, however, the buttons formed by it is not clickable,i don't understand what i am doing wrong
And there are no example given, or no question asked
What would be the correct way of using this pagination
Here is the code of my App.js
import React, { Component } from 'react';
import './App.css';
import Navbar from '../src/components/navbar/navbar'
import SearchIt from '../src/components/searchField/search'
import Container from 'react-bootstrap/Container'
import Card from '../src/components/cards/cards'
import Axios from 'axios'
import Pagination from '../src/components/pagination/paginating'
class App extends Component {
state={
fetchedData:[]
}
componentDidMount(){
Axios.get('http://localhost:3000/1').then((responseData)=>{
//console.log(responseData.data)
this.setState({fetchedData:responseData.data})
}).catch((err)=>{
console.log(err)
})
}
handlePageClicked = data => {
let selected = data.selected;
console.log(selected)
};
render() {
return (
<div className="App">
<Navbar/>
<Container>
<SearchIt/>
<Card data={this.state.fetchedData}/>
<Pagination handlePageClick={this.handlePageClicked}/>
</Container>
</div>
);
}
}
export default App;
And here is the code for paginating.js
import React,{Component} from 'react'
import ReactPaginate from 'react-paginate';
import './paginateStyle.css'
const page = (props)=>{
return(
<ReactPaginate
previousLabel={'previous'}
nextLabel={'next'}
breakLabel={'...'}
breakClassName={'break-me'}
pageCount={10}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={props.handlePageClick}
containerClassName={'pagination'}
subContainerClassName={'pages pagination'}
activeClassName={'active'}
/>
)
}
export default page
These button are not clickable
I did a quick sample and it worked.
import ReactPaginate from 'react-paginate';
const Pagination = (props) => {
return (
<ReactPaginate
previousLabel={'previous'}
nextLabel={'next'}
breakLabel={'...'}
breakClassName={'break-me'}
pageCount={10}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={props.handlePageClick}
containerClassName={'pagination'}
subContainerClassName={'pages pagination'}
activeClassName={'active'}
/>
)
}
class App extends Component {
state = {
selectedPage: 0
}
handlePageClicked = data => {
let selected = data.selected;
this.setState({
selectedPage: selected
})
console.log(selected)
};
render() {
return (
<React.Fragment>
<div>You selected: {this.state.selectedPage}</div>
<div className="App">
<Pagination handlePageClick={this.handlePageClicked} />
</div>
</React.Fragment>
);
}
}
There could be something in paginateStyle.css which is making the Pagination not work properly or some other CSS in your application.
EDIT:
From comments, a ui component with higher z index was over them and was not visible/clickable
This question already has answers here:
Unable to pass props to component through react-router
(3 answers)
When I link javascript file in html it sends a request to server and causing error
(3 answers)
Closed 4 years ago.
I am having a trouble with this minor problem . When i refresh my page , it gives an error `
GET http://localhost:3000/drink/bundle.js net::ERR_ABORTED 404 (Not Found)
Refused to apply style from 'http://localhost:3000/drink/style.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
I know that this a problem with rout but i couldnt find a way to solve it .
Here is my code `
import * as React from "react"; import {connect} from "react-redux"; import {drinksSelector} from "../selectors" import {getDrinksList, getNameFilter} from "../actions"; import Drink from "./Drink"; import SearchIcon from "./SvgIcons";
class Drinks extends React.Component {
componentDidMount() {
this.props.dispatchDrinksList();
}
handleInputChange = (e: any) => {
e.preventDefault();
this.props.dispatchNameFilter(e.target.value) }
render() {
const {drinks} = this.props;
return (
<div>
<header className="main-header">
<form className="main-header__from">
<div className="search-wrapper">
<input autoComplete='off'
type="text"
name="search"
placeholder="Search"
className="main-header__input"
onChange={this.handleInputChange}/>
<SearchIcon />
</div>
</form>
</header>
<ul>
{drinks.map((drink: any) => <Drink key={drink.idDrink} url={drink.strDrinkThumb} name={drink.strDrink} id={drink.idDrink}/>)}
</ul>
</div>
); } } const mapStateToProps: any = (state: any) => drinksSelector(state);
const mapDispatchToProps: any = (dispatch: ReturnType<typeof mapDispatchToProps>) => ({ dispatchDrinksList() {
dispatch(getDrinksList()); },
dispatchNameFilter(value: any) {
dispatch(getNameFilter(value));
} });
export default connect(mapStateToProps, mapDispatchToProps)(Drinks);
Above is the dashboard page where i render list of drinks, and when clicking on them the routes changes to /drink/someId
import * as React from 'react'; import { connect } from 'react-redux';
import { NavLink } from "react-router-dom";
const Drink = ({ url = "", name, id }: any): any => (
<li>
<NavLink to={`/drink/${id}`}>
<h2>{name}</h2>
<img src={url} alt={name} height="350" width="350"/>
</NavLink>
</li> );
export default Drink;
And this is the page where after refreshing i got an error `
import * as React from 'react';
import { connect } from 'react-redux';
import { NavLink } from "react-router-dom";
import {getDrinkInfo} from "../actions";
class DrinkInfo extends React.Component<any, any> {
componentDidMount() {
const id = localStorage.getItem("id");
if (!id) {
localStorage.setItem("id", this.props.match.params.id);
}
this.props.dispatchDrinkInfo(localStorage.getItem("id"));
}
render() {
const { drink } = this.props;
console.log(this.props, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
return (
<div className="drink-info">
<header className="drink-info__header">
<button onClick={() => this.props.history.goBack()} className="drink-info__button">Go Back</button>
<h2 className="drink-info__title">{drink && drink.strDrink}</h2>
</header>
<section className="details">
<div className="details__image-box">
<img src={drink && drink.strDrinkThumb} alt={drink && drink.strDrink} height="350" width="350"/>
</div>
<div className="details__info">
<p className="details__ingredients"></p>
<div className="details__prepare">
<h3 className="details__prepare-heading">How to prepare</h3>
<p className="details__prepare-text">
{drink && drink.strInstructions}
</p>
</div>
</div>
</section>
</div>
)
}
}
const mapStateToProps: any = (state: any) => {
return {
drink: state.drink.get("drinkInfo") || {}
}
}
const mapDispatchToProps: any = (dispatch: ReturnType<typeof mapDispatchToProps>) => ({
dispatchDrinkInfo(id: number) {
dispatch(getDrinkInfo(id));
}
});
export default connect(mapStateToProps, mapDispatchToProps)(DrinkInfo);
My routers `
import * as React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import DashboardPage from '../components/DashboardPage';
import DrinkInfo from '../components/DrinkInfo';
import NotFoundPage from '../components/NotFoundPage';
const AppRouter = () => (
<BrowserRouter>
<React.Fragment>
<Switch>
<Route path="/" component={DashboardPage} exact/>
<Route path="/drink/:id" component={DrinkInfo}/>
<Route component={NotFoundPage} />
</Switch>
</React.Fragment>
</BrowserRouter>
);
export default AppRouter;
I successfully load data from the OpenDota API but somehow, the images
are broken when I pass the image props in my Heroes.js
here is the Component where I load the API.
HeroStats.js
import React, { Component } from 'react'
import Sidebar from "./Sidebar";
import Heroes from "./Heroes"
import "./App.css"
import axios from "axios";
const URL = "https://api.opendota.com/api/heroStats";
class HeroStats extends Component {
state = {
data: []
}
componentDidMount() {
axios.get(URL)
.then(res => {
this.setState({
data: res.data
});
});
}
render() {
const Stats = this.state.data.map(stat => (
<Heroes
key={stat.id}
id={stat.id}
name={stat.name}
localized_name={stat.localized_name}
img={stat.img}
icon={stat.icon}
pro_win={stat.pro_win}
pro_pick={stat.pro_pick}
pro_ban={stat.pro_ban}
/>
))
return (
<div>
{Stats}
</div>
)
}
}
export default HeroStats;
and here where I pass my props.
Heroes.js
import React from 'react'
const Heroes = (props) => (
<div>
<h1>{props.localized_name}</h1>
<img src={props.img} />
<img src={props.icon} />
<h1>{props.pro_win}</h1>
<h1>{props.pro_pick}</h1>
<h1>{props.pro_ban}</h1>
</div>
)
export default Heroes;
also if I use other tag like <h1>{props.img}</h1> it shows the image file path. did I miss something that i should include?
the value of img is not the full url you need to do this
const Heroes = (props) => (
<div>
<h1>{props.localized_name}</h1>
<img src={"https://api.opendota.com" + props.img} />
<img src={"https://api.opendota.com" + props.icon} />
<h1>{props.pro_win}</h1>
<h1>{props.pro_pick}</h1>
<h1>{props.pro_ban}</h1>
</div>
)