looping json data in Class Component - reactjs

This is my index.js where I try to refer SampleApp
import React, { Component } from "react";
import { render } from "react-dom";
import './index.css';
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect
} from "react-router-dom";
import SampleApp from "./pages/SampleApp";
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends Component {
constructor() {
super();
this.state = {
name: "React",
isUserAuthenticated: true
};
}
render() {
return (
<Router>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/SampleApp" />
)
}}
/>
<Route exact path="/SampleApp" component={SampleApp} />
</Switch>
</Router>
);
}
}
render(<App />, document.getElementById("root"));
This is my SampleApp.js file. here I'm importing the Cards component from Cards.jsx
import React from 'react';
import '../../src/App.css';
import Cards from '../cards/cards';
const SampleApp = props => (
<React.Fragment>
<div className="App">
<div>
<div className="header">
<div className="header_fonts">
Sample Application
</div>
</div>
<div>
<div className="content_header_fonts">
This is sample app
</div>
<div className="content_fonts">
Sample app to deomntrate ideas.
</div>
<Cards></Cards>
</div>
</div>
</div>
</React.Fragment>
)
export default SampleApp;
this is my Cards.jsx file.
here I'm importing Card component and json data
import React, { Component } from "react";
import Card from './cardUI';
import CardData from '../source/data.json';
class Cards extends Component {
render() {
return
(
<div className="container-fluid d-flex justify-content-center">
<div className="row">
{
CardData.map((
{title, desc, icon, intro,developer_guide,api_ref }, id) =>
(
<div className="col-md-4">
<Card
title={title}
desc={desc}
intro={intro}
developer_guide={developer_guide}
api_ref={api_ref}/>
</div>
))
}
</div>
</div>
);
}
}
export default Cards;
this is a sample of my JSON file
[
{
"id" : 7,
"title" : "Melon Munchee",
"icon" : "https://cdn.onlinewebfonts.com/svg/img_393496.png",
"desc" : "If you are an Avatar fan, then this api is for you. Here you can find everything from Episodes to Characters.",
"intro": "intro_7",
"developer_guide": "d_link7",
"api_ref": "api_link7"
},
{
"id" : 8,
"title" : "Browns Barns",
"icon" : "https://cdn.onlinewebfonts.com/svg/img_386567.png",
"desc" : "Baseball fans? Computer nerds? Now, in one place, you have baseball data and an api to access it. Have fun!.",
"intro": "intro_8",
"developer_guide": "d_link8",
"api_ref": "api_link8"
}
]
Card.jsx file
This is how implemented the Card component
import React from 'react';
import "../../node_modules/bootstrap/dist/css/bootstrap.min.css";
import * as Icon from '../../node_modules/react-bootstrap-icons';
import './card-style.css';
const Card = props =>{
return(
<div className="card text-center">
<div className="card-body text-dark">
<Icon.Alarm></Icon.Alarm>
<h4 className="card-title">
{props.title}
</h4>
<p className="card-text text-secondary">
{props.desc}
</p>
<ul class="list-group">
<li class="list-group-item">{props.intro}</li>
<li class="list-group-item">{props.developer_guide}</li>
<li class="list-group-item">{props.api_ref}</li>
</ul>
</div>
</div>
)
}
export default Card;
but I'm getting an error as following
Error: Cards(...): Nothing was returned from render. This usually
means a return statement is missing. Or, to render nothing, return null.
19 stack frames were collapsed. Module.
src/index.js:44 41 | } 42 | } 43 |
44 | render(, document.getElementById("root"));

I am actually going to take a guess here and say that your specific error is caused by the new line after your return statement. So remove it to make it look like this return ( and it should work... or at least that error should go away.
Check out this sandbox: https://codesandbox.io/s/xenodochial-fog-y8pk2?file=/src/App.js
just go ahead and add a new line after the return and see your exact error.

It's just a typo mistake. When you use line terminator next to the return statement, JS adds semicolon automatically and that will be the end of function execution and returns undefined. That's why your Cards component is not able to find the JSX because Cards render returns undefined.
As per MDN docs.
The return statement is affected by automatic semicolon insertion (ASI). No line terminator is allowed between the return keyword and the expression.
To fix this, update Cards render function with this
class Cards extends Component {
render() {
return ( // was the issue earlier
<div className="container-fluid d-flex justify-content-center">
<div className="row">
{
CardData.map(({ title, desc, icon, intro,developer_guide,api_ref }, index) => (
<div className="col-md-4" key={title + index}>
<Card
title={title}
desc={desc}
intro={intro}
developer_guide={developer_guide}
api_ref={api_ref} />
</div>
)
)
}
</div>
</div>
);
}
}

Related

My Component isn't conditionally rendering properly

I have a simple react page so far where I just have a home component which seems to work fine it is made up from the code I have included what I am trying to do is to render another component the main component when the button that is part of the home component is clicked but it keeps giving me the error and I have no idea what I am doing wrong in this case I have included code for all of my files the main component isn't fully finished right now it was just to test what I am currently doing that I added a paragraph placeholder any help is appreciated thanks
Error: Unknown error
(/node_modules/react-dom/cjs/react-dom.development.js:3994) !The above
error occurred in the component: at Main (exe1.bundle.js:94:3)
at div at App (exe1.bundle.js:31:52) Consider adding an error boundary
to your tree to customize error handling behavior. Visit
https://reactjs.org/link/error-boundaries to learn more about error
boundaries. !Error: Unknown error
Home Component:
import React from "react";
export default function Home(props) {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner">
</div>
<div className="top-corner">
</div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button
className="start-button"
onClick={props.handleClick}
>Start quiz
</button>
</div>
</main>
)
}
Main Component:
import react from "react";
export default function Main() {
return (
<h1>hello </h1>
)
}
App:
import React from "react";
import Main from "./components/Main"
import Home from "./components/Home"
export default function App() {
const [startQuiz, setStartQuiz] = React.useState(false);
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(prevState => !prevState);
}
return (
<div>
{console.log("start", startQuiz)}
{startQuiz ?
<Main />
:
<Home handleClick={clickStart}/> }
}
</div>
)
}
Index:
import React from "react"
import ReactDOM from "react-dom"
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"))
I think you just have a typo here
import react from "react";
should be
import React from "react";
You can try changing your setStartQuiz to just simply negate the current startQuiz value instead of using prevState.
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(!startQuiz);
}
Here's a working example based on your code.
code sandbox
import React, { useState } from "react";
const Main = () => <h1>hello </h1>;
const Home = (props) => {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner"></div>
<div className="top-corner"></div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button className="start-button" onClick={props.handleClick}>
Start quiz
</button>
</div>
</main>
);
};
export default function App() {
const [startQuiz, setStartQuiz] = useState(false);
return (
<div>
{startQuiz && <Main />}
{!startQuiz && <Home handleClick={() => setStartQuiz(true)} />}
</div>
);
}

Caching in Gatsby JS

I have this Gatsby app where when I visit home page everything loads at first including the Testimonials section. However, when I visit another page, for instance the Blog list page and then click on the link back to homepage the data on Testimonials component won't load and you will see a blank area of the app where the Testimonials section is placed. In order to see the Testimonials list, you will have the refresh the page again.
For the record the data on my Testimonials component are being pulled out on Strapi JS that is deployed on Heroku.
So far I got this on my index.js:
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/Layout"
import Header from "../components/Header"
import Testimonials from '../components/Testimonials'
import Blogs from '../components/Blogs'
import SEO from '../components/SEO'
export default function Home({ data }) {
const {
allStrapiBlogs: { nodes:blogs },
} = data
return (
<>
<SEO />
<div className="main-container">
<Layout>
<Header />
<Testimonials title="Testimonials" />
<Blogs title="Latest Blogs" blogs={blogs} showAllBlogLinks/>
<Map />
</Layout>
</div>
</>
)
}
export const query = graphql`
{
allStrapiBlogs(filter: {featured: {eq: true}}, sort: {fields: published_date, order: DESC}, limit: 6) {
nodes {
id
title
content
slug
published_date(formatString: "MMMM DD, YYYY")
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
And then on my Testimonials.js component:
import React from "react"
import { graphql, useStaticQuery } from "gatsby"
import Image from "gatsby-image"
import { FaStar } from "react-icons/fa"
import Title from './Title'
const query = graphql`
{
allStrapiTestimonials {
nodes {
id
name
cite
text
photo {
childImageSharp {
fluid{
...GatsbyImageSharpFluid_withWebp
}
}
}
}
}
}
`
const Testimonials = ({ title }) => {
const data = useStaticQuery(query)
const { allStrapiTestimonials: { nodes:testimonials } } = data
return (
<div className="testimonial-section section-padding" id="testimonial" data-aos="zoom-in">
<div className="container">
<div className="row">
<div className="col-lg-12">
<div className="section-title-two center">
<Title title={title} />
</div>
</div>
</div>
<div className="testimonial-wrap row">
<div className="testimonial-slider owl-carousel">
{ testimonials.map(item => {
const { id, name, cite, text, photo } = item
return(
<div className="col-xl-8 col-lg-10 col-12 ml-auto mr-auto" key={id}>
<div className="testimonial-item mt-40">
<div className="testimonial_img">
<Image fluid={photo.childImageSharp.fluid} alt={name} style={{ position: "absolute", overflow: "visible", display: "block", width: "211px", height: "207px" }} />
</div>
<div className="testimonial_content xs-mt-40">
<div className="testimonial_content_item mb-30">
<div className="testimonial_content__pro">
<h4 className="mb-10">{ name }</h4>
<p>{ cite }</p>
</div>
<ul className="d-none d-sm-inline-block">
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
</ul>
</div>
<div>
<p>{ text } </p>
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
</div>
</div>
)
}
export default Testimonials
Any idea what's causing this error? How can I fix it?
I've faced a similar issue a few months ago and the fix depends strictly on the implementation and your code. Basically, what is happening is that React's doesn't understand that he needs to rehydrate some components because pointing to some global objects as window or document of the DOM, outside the React's ecosystem (without using states) may block that rehydration, in your cause, because of jQuery.
All the possible solutions that bypass this issue will be patches (like trying to add the cache). The ideal solution would avoid using jQuery, which points directly to the DOM, with React, which manipulates the virtual DOM (vDOM).
There's nothing wrong with the code you've shared, however, based on some other questions that you did, you are using jQuery and using the window object, which prevents the rehydration of some React components. You should get rid of jQuery or using some React-based approach. Something like this should do the trick to force a loader across the whole site:
const Layout = ({ children }) => {
const [loader, setLoader]=useState(true);
useEffect(()=>{
setTimeout(()=> {
setLoader(false)
}, 400)
}, [])
return <section className={`site__wrapper`}>
<Header />
<main>{loader ? <Preloader/> : children}</main>
</section>;
};

Trying to append an API value to a controlled input field with React Hooks

When the component loads, I am making an axios call to a Geolocation API. If the user agrees to let the app get their location, it gets their zipcode. I am then trying to append the zipcode to the zipcode input field, but I can't figure out how to do it. This is my landing page.
import React, { useState, useEffect, useRef } from 'react';
import './App.scss';
import axios from 'axios';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faBars } from '#fortawesome/free-solid-svg-icons';
import LandingPage from './components/landingPage';
function App() {
const[zipcode, setZipcode] = useState();
useEffect(() => {
axios({
"method":"GET",
"url":"https://find-any-ip-address-or-domain-location-world-wide.p.rapidapi.com/iplocation",
"headers":{
"content-type":"application/octet-stream",
"x-rapidapi-host":"find-any-ip-address-or-domain-location-world-wide.p.rapidapi.com",
"x-rapidapi-key":x-rapidapi-key,
"useQueryString":true
},
"params":{
"apikey":apikey
}
})
.then((response)=>{
console.log(response.data.zipCode);
setZipcode(response.data.zipCode);
})
.catch((error)=>{
console.log(error)
});
},[]);
return (
<div className="App" path='/'>
<header className='container'>
<div className='row'>
<div className='col-1'>
<button>
<h1><FontAwesomeIcon icon={faBars} /></h1>
</button>
</div>
<div className='col'>
<h1>MDNight</h1>
</div>
</div>
</header>
<LandingPage zipcode={zipcode} setZipcode={setZipcode} />
<footer className='container'>
<h2>Copyright 2020</h2>
</footer>
</div>
);
}
export default App;
And here is the child component.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function LandingPage(props) {
function handleInputChange(e) {
props.setZipcode(e.target.value);
};
return (
<main className='container'>
<div className='row'>
<div className='col'>
<h1>Welcome to <span>MDNight</span>!</h1>
<h2>The website that makes your date night more convenient.</h2>
<p>Let's assume that you and your "Significant Other" would like to go out for a date night, however, you have to continually switch back and forth between websites looking at showtimes and trying to find a place to eat beforehand. Well, that's where <span>MDNight</span> comes in! We take your location, movie you're interested in seeing, , and show you theaters that are showing your movie, and a list of restaurants nearby. Sound Convenient to you? Enter your info below to get started!</p>
</div>
</div>
<div className='row'>
<div className='col'>
<label htmlFor='zipcodeInput'>Please Enter Your zipcode to get started!</label>
</div>
</div>
<div className='row'>
<div className='col'>
<input name='zipcodeInput' type="text" value={props.zipcode} onChange={handleInputChange} />
</div>
</div>
<div className='row'>
<div className='col'>
<button className='btn btn-primary'>Get Started!</button>
</div>
</div>
</main>
);
}
export default LandingPage;
I've only ever used useState and useEffect, so I don't know if one of the other hooks solves this problem, but if someone could show me how that would be amazing.
I found this answer from someone on a React FB group. I added defaultValue={props.zipcode} to the input and it worked perfectly. I did not know about defaultValue until today.
You do not need zipcode as a dependency of the useEffect hook in the App component. I would suggest having an empty array as your dependency array because you want this hook to run on mount only.

Using fullpagejs in React, how to trigger function on active slide without re-rendering entire page

In my React app I am using fullpage.js to render two slides containing two different components. I want to run a function inside one of these only when it's the active slide. I tried below code, but once the state changes the entire ReactFullpage is re-rendered causing the first slide to be active again so I'm basically stuck in a loop.
My question is, how can I trigger a function inside the <Player /> component to run only if it's the active slide?
import React from "react";
import ReactFullpage from "#fullpage/react-fullpage";
import AlbumInfo from './AlbumInfo';
import Player from './Player';
class Album extends React.Component {
constructor(props){
super(props);
this.state={
playing: false
}
}
_initPlayer = (currentIndex, nextIndex) => {
if(nextIndex.index === 1) {
this.setState({playing:true})
}
}
render() {
return (
<ReactFullpage
licenseKey='xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx'
sectionsColor={["#000000"]}
afterLoad={this._initPlayer}
render={({ state, fullpageApi }) => {
return (
<div id="fullpage-wrapper">
<div className="section">
<AlbumInfo />
</div>
<div className="section">
<Player playing={this.state.playing} />
</div>
</div>
);
}}
/>
);
}
}
export default Album;
From docs:
just add the class 'active' to the section and slide you want to load first.
adding conditionally (f.e. using getActiveSection()) 'active' class name should resolve rerendering problem.
The same method/value can be used for setting playing prop.
Probably (I don't know/didn't used fullpage.js) you can also use callbacks (without state management and unnecessary render), f.e. afterSlideLoad
Update
The issue has been fixed on https://github.com/alvarotrigo/react-fullpage/issues/118.
Version 0.1.15 will have it fixed
You should be using fullPage.js callbacks afterLoad or onLeave as can be seen in the codesandbox provided on the react-fullpage docs:
https://codesandbox.io/s/m34yq5q0qx
/* eslint-disable import/no-extraneous-dependencies */
import React from "react";
import ReactDOM from "react-dom";
import "fullpage.js/vendors/scrolloverflow"; // Optional. When using scrollOverflow:true
import ReactFullpage from "#fullpage/react-fullpage";
import "./styles.css";
class FullpageWrapper extends React.Component {
onLeave(origin, destination, direction) {
console.log("Leaving section " + origin.index);
}
afterLoad(origin, destination, direction) {
console.log("After load: " + destination.index);
}
render() {
return (
<ReactFullpage
anchors={["firstPage", "secondPage", "thirdPage"]}
sectionsColor={["#282c34", "#ff5f45", "#0798ec"]}
scrollOverflow={true}
onLeave={this.onLeave.bind(this)}
afterLoad={this.afterLoad.bind(this)}
render={({ state, fullpageApi }) => {
return (
<div id="fullpage-wrapper">
<div className="section section1">
<h3>Section 1</h3>
<button onClick={() => fullpageApi.moveSectionDown()}>
Move down
</button>
</div>
<div className="section">
<div className="slide">
<h3>Slide 2.1</h3>
</div>
<div className="slide">
<h3>Slide 2.2</h3>
</div>
<div className="slide">
<h3>Slide 2.3</h3>
</div>
</div>
<div className="section">
<h3>Section 3</h3>
</div>
</div>
);
}}
/>
);
}
}
ReactDOM.render(<FullpageWrapper />, document.getElementById("react-root"));
export default FullpageWrapper;

Can only update a mounted or mounting component. due to Router

I want to write a musicplayer with react.js. After init works ths player well.
But once I change the site with router to music list, the console show me the error:
Can only update a mounted or mounting component. This usually means
you called setState() on an unmounted component. This is a no-op.
Please check the code for the Player component
I have marked the line in code.
I think, while I am changing the site, the player component may be unmounted. But wihtout the componentWillUnmount function, nothing different.
Here is my project.
Thanks in advance!
player.js
import React, {Component} from 'react';
import '../../styles/player.less';
import Progress from '../commen/progress.js';
import {Link} from 'react-router-dom';
let duration = null;
export default class Player extends Component {
constructor(props){
super(props);
this.state={
progress: 0,
volume: 0,
isPlay: true,
},
this.play=this.play.bind(this);
this.progressChangeHandler=this.progressChangeHandler.bind(this);
this.volumeChangeHandler=this.volumeChangeHandler.bind(this);
}
componentDidMount(){
$('#player').bind($.jPlayer.event.timeupdate,(e)=>{
duration = e.jPlayer.status.duration;//total duration of the song
this.setState({//here is the problem !!!!!!!!!!!!!!!!!!!!!!!
volume: e.jPlayer.options.volume*100,
progress:e.jPlayer.status.currentPercentAbsolute
});//how lange already played
});
}
componentWillUnMount(){
//$('#player').unbind($.jPlayer.event.timeupdate);
}
//从子组件中获得值
//change progress
progressChangeHandler(progress){
$('#player').jPlayer('play', duration * progress);
}
//change volume
volumeChangeHandler(progress){
$('#player').jPlayer('volume', progress);
}
//play pause switcher
play(){
if(this.state.isPlay){
$('#player').jPlayer('pause');
}else{
$('#player').jPlayer('play');
}
this.setState({
isPlay: !this.state.isPlay,
})
}
render(){
return(
<div className="player-page">
<h1 className="caption">
<Link to="/list">My Favorite Music</Link>
</h1>
<div className="mt20 row">
<div className = "controll-wrapper">
<h2 className="music-title">{this.props.currentMusicItem.title}</h2>
<h3 className="music-artist mt10">{this.props.currentMusicItem.artist}</h3>
<div className="row mt20">
<div className="left-time -col-auto">-2:00</div>
<div className="volume-container">
<i className="icon-volume rt"></i>
<div className="volume-wrapper">
<Progress
progress={this.state.volume}
onProgressChange={this.volumeChangeHandler}
barColor="#aaa"></Progress>
</div>
</div>
</div>
<div className="progress-container">
<Progress
progress={this.state.progress}
onProgressChange={this.progressChangeHandler}>
</Progress>
</div>
<div className="mt35 row">
<div>
<i className="icon prev"></i>
<i className={`icon ml20 ${this.state.isPlay ? 'pause' : 'play'}`} onClick={this.play}></i>
<i className="icon next ml20"></i>
</div>
<div className="-col-auto">
<i className="icon repeat-cycle"></i>
</div>
</div>
</div>
<div className="-col-auto cover">
<img src={this.props.currentMusicItem.cover} alt={this.props.currentMusicItem.title}/>
</div>
</div>
</div>
/**<div className="player-page">
<Progress progress={this.state.progress} onProgressChange={this.progressChangeHandler}></Progress>
</div>**/
)
}
}
root.js
import React, {Component} from 'react';
import Header from './commen/header.js';
import Player from './page/player.js';
import {MUSIC_LIST} from '../config/musiclist';
import MusicListUI from './page/musiclistui.js';
import {BrowserRouter as Router, Switch, Route, Link} from 'react-router-dom';
export default class Root extends Component{
constructor(props){
super(props);
this.state={
musiclist: MUSIC_LIST,
currentMusicItem: MUSIC_LIST[0]
}
}
componentDidMount(){
$('#player').jPlayer({
ready:function(){
$(this).jPlayer('setMedia',{
mp3:'http://oj4t8z2d5.bkt.clouddn.com/%E9%AD%94%E9%AC%BC%E4%B8%AD%E7%9A%84%E5%A4%A9%E4%BD%BF.mp3'
}).jPlayer('play');
},
supplied:'mp3',
wmode: 'window'
});
}
render(){
const Home=() => (
<Player
currentMusicItem={this.state.currentMusicItem}
/>
);
const List = () => (
<MusicListUI
currentMusicItem={this.state.currentMusicItem}
musiclist={this.state.musiclist}
/>
);
return(
<Router>
<div>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list" component={List}/>
</Switch>
</div>
</Router>
)
}
}
Error sums it up well. When you change the route component gets unmounted and callback tries to setState on unmounted component. You have to figure out how to do clean up before this happens. I see you already figured out that you can use componentWillUnmount, but you have a typo:
componentWillUnMount(){ // should be componentWillUnmount!
//$('#player').unbind($.jPlayer.event.timeupdate);
}
Notice also that bind method has been deprecated.
Router is not your issue. Your issue is that you are fighting a fundamental design paradigm of React... or perhaps common sense. You are not supposed to try and perform operations on components that don't currently don't exist. What would that accomplish? In your case, you have a bunch of event listeners that you haven't removed.
As a side note, you are using an incredible amount of jQuery. You should be using this.setState as often as you can. You're programming in a style that goes against some of the best aspects of React.

Resources