No Set State or Async but still "Can't perform state update on unmounted component" error - reactjs

I have nearly given up with this. I can't get my component to work no matter what I do. I have read all the error posts here and on Google but still nothing. I get the error
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
Here is my full code...
import React, { Component } from 'react;
// page title bar
import PageTitleBar from 'Components/PageTitleBar/PageTitleBar';
import {
NewsFeedWidget
} from "Components/Widgets";
// widgets data
import {
newsData,
} from './data';
export default class EcommerceDashboard extends Component {
render() {
return (
<div className="ecom-dashboard-wrapper">
<div className="content_container">
<div className="row">
<div className="col-sm-6 col-md-4 w-xs-full">
<NewsFeedWidget data={newsData} />
</div>
</div>
</div>
</div>
)
}
}
and NewsFeed.js
import React, { Component, Fragment } from 'react';
const NewsFeedWidget = ({ data }) => (
<div className="cardheader_container">
<div className="notification_container">
{data && data.map((d, key) => (
<div className="a_notification" key={key}>
<div className="not_header">
<div className="not_content">
<h5>{d.title}</h5>
<p>{d.subtitle}</p>
</div>
</div>
</div>
))}
</div>
</div>
}
export default NewsFeedWidget;
Obviously I am new at React so please explain how and what issue I am having. It's gonna be something dumb I bet but this is how i'll learn.
ty

Could you upload the code for PageTitleBar too ?

Related

Can someone tell me why my app crashes when I refresh the page?

I added a weather component in my app that fetches weather from open weather map. It works fine until I refresh the page, then it breaks.
If I comment the weather component out when refreshing and then add it back in when loaded it renders and works.
I'm not sure what's causing this error.
Here's some images of the console after refreshing for reference.
It seems to be undefined when refreshed. What's causing this issue?
// Weather component is called as normal in Home page
<div className="main-section-one">
<Weather />
<ToDoWidget />
</div>
import React, { useEffect, useState } from 'react'
//CSS
import '../css/Weather.css'
function Weather() {
// API
const URL = 'https://api.openweathermap.org/data/2.5/weather?q=barcelona&appid=APIKEY';
// State
const [weatherDetails, setWeatherDetails] = useState({});
async function getWeather() {
let fetchUrl = await fetch('https://api.openweathermap.org/data/2.5/weather?q=barcelona&appid=APIKEY&units=metric');
let data = await fetchUrl.json()
setWeatherDetails(data)
}
//Use Effect
useEffect(() => {
getWeather();
}, [])
return (
<div className="weather-container">
<div className="weather-one">
<div className="city">
<h3>Barcelona</h3>
<h1 className='temp'>{weatherDetails.main.temp}°C</h1>
</div>
<div className="current-weather">
<h3 className='current'>Sunny</h3>
</div>
</div>
<div className="weather-two">
<div className="">
<p>{weatherDetails.main.feels_like}°C</p>
<p className='weather-details'>Feels Like</p>
</div>
<div className="">
<p>{weatherDetails.main.humidity}%</p>
<p className='weather-details'>Humidity</p>
</div>
<div className="">
<p>{weatherDetails.wind.speed} MPH</p>
<p className='weather-details'>Wind Speed</p>
</div>
</div>
</div>
)
}
export default Weather
The main and wind properties may be undefined. Secure it.
<h1 className='temp'>{weatherDetails.main?.temp}°C</h1>
^^^ optional chaining
<p>{weatherDetails.wind?.speed} MPH</p>
Reference: Optional chaining

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.

How to trigger a function from one component to another component in React.js?

I'am creating React.js Weather project. Currently working on toggle switch which converts celcius to fahrenheit. The celcius count is created in one component whereas toggle button is created in another component. When the toggle button is clicked it must trigger the count and display it. It works fine when both are created in one component, but, I want to trigger the function from another component. How could I do it? Below is the code for reference
CelToFahr.js (Here the count is displayed)
import React, { Component } from 'react'
import CountUp from 'react-countup';
class CeltoFahr extends Component {
state = {
celOn: true
}
render() {
return (
<React.Fragment>
{/* Code for celcius to farenheit */}
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CountUp
start={!this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
end={this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
duration={2}
>
{({ countUpRef, start}) => (
<h1 ref={countUpRef}></h1>
)}
</CountUp>
</div>
</div>
</div>
</div>
{/*End of Code for celcius to farenheit */}
</React.Fragment>
)
}
}
export default CeltoFahr
CelToFahrBtn (Here the toggle button is created)
import React, { Component } from 'react'
import CelToFahr from './CeltoFahr'
class CelToFahrBtn extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render = (props) => {
return (
<div className="button" style={{display: 'inline-block'}}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={this.switchCel} className="CelSwitchWrap">
<div className={"CelSwitch" + (this.state.celOn ? "" : " transition")}>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CelToFahrBtn
Here when I click on switchCel it must trigger the celcius to fahrenheit value and vice-versa. How to do it? Any suggestions highly appreciated. Thanks in advance
I would have the celToFahr be the parent component of the celToFahrBtn and then pass the function you want to invoke via props
<CellToFahrBtn callback={yourfunction}/>
What else could you do is having a common parent for these to components where you would again do the execution via props and callbacks
The 3rd option would be having a global state which would carry the function like Redux or Reacts own Context. There again you would get the desired function via props and you would execute it whenever you like. This is the best option if your components are completely separated in both the UI and in source hierarchically, but I don't think this is the case in this case.
https://reactjs.org/docs/context.html
These are pretty much all the options you have
To achieve this you'd need to lift your state up and then pass the state and handlers to the needed components as props.
CeltoFahr & CelToFahrBtn would then become stateless components and would rely on the props that are passed down from TemperatureController
class TemperatureController extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render () {
return (
<React.Fragment>
<CeltoFahr celOn={this.state.celOn} switchCel={this.state.switchCel} />
<CelToFahrBtn celOn={this.state.celOn} switchCel={this.state.switchCel}/>
</React.Fragment>
)
}
}
It's probably better explained on the React Docs https://reactjs.org/docs/lifting-state-up.html
See this more simplified example:
import React, {useState} from 'react';
const Display = ({}) => {
const [count, setCount] = useState(0);
return <div>
<span>{count}</span>
<Button countUp={() => setCount(count +1)}></Button>
</div>
}
const Button = ({countUp}) => {
return <button>Count up</button>
}
It's always possible, to just pass down functions from parent components. See Extracting Components for more information.
It's also pretty well described in the "Thinking in React" guidline. Specifically Part 4 and Part 5.
In React you should always try to keep components as dumb as possible. I always start with a functional component instead of a class component (read here why you should).
So therefore I'd turn the button into a function:
import React from 'react';
import CelToFahr from './CeltoFahr';
function CelToFahrBtn(props) {
return (
<div className="button" style={{ display: 'inline-block' }}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={() => props.switchCel()} className="CelSwitchWrap">
<div
className={'CelSwitch' + (props.celOn ? '' : ' transition')}
>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default CelToFahrBtn;
And you should put the logic in the parent component:
import React, { Component } from 'react';
import CountUp from 'react-countup';
import CelToFahrBtn from './CelToFahrBtn';
class CeltoFahr extends Component {
state = {
celOn: true
};
switchCel = () => {
this.setState({ celOn: !this.state.celOn });
};
render() {
return (
<>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CelToFahrBtn switchCel={this.switchCel} celOn={celOn} />
</div>
</div>
</div>
</div>
</>
);
}
}

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