Warning: Cannot update a component (`BrowserRouter`) while rendering a different component ('something') - javascript

I have tried everything but no solution. Please anybody help.
my partial code:
socialLogin.js
const SocialLogin = () => {
const [signInWithGoogle, googleUser, googleLoading, googleError] =
useSignInWithGoogle(auth);
return (
<div>
<div className=" d-flex justify-content-evenly ">
<button
onClick={() => signInWithGoogle()}
type="submit"
className="btn btn-outline-primary"
>
<img className="px-2" src={google} alt="" />
Sign in with Google
</button>
</div>
</div>
);
};
export default SocialLogin;

Related

onClick of button triggering all the components to open - Reactjs

I implemented a Card component and basically generating a bunch of cards on some input data. I binded a setter function on button click on every card which basically expands and collapse it. Even after putting unique keys to the div is sort of triggering all the cards to open at once.
Here is the code piece:
import React, { useState } from 'react';
import PrettyPrintJson from './PrettyPrintJson';
import './Card.scss';
import '../App.scss';
const Card = (props) => {
const { data } = props;
const [collapse, toggleCollapse] = useState(true);
return (<div className="card-group">
{data.map((obj, idx)=>{
return <div className="card" key={`${idx}_${obj?.lastModifiedOn}`}>
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapse(!collapse)}>Show Json</button>
</div>
</div>
<div className={`card-content ${!collapse ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>
})}
</div>
);
}
export default Card;
Create a component that manages it's own state and render that component.
const CardItem = ({ obj }) => {
const [collapse, toggleCollapse] = useState(true);
return (<div className="card">
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapse(!collapse)}>Show Json</button>
</div>
</div>
<div className={`card-content ${!collapse ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>)
}
then render it like
{data.map((obj, idx)=> (<CardItem obj={obj} key={idx} />))}
I think you can declare a state which is a type of int. After then, you can use the if-statement of index(idx) and state.
Like this:
const [collapsedCardNumbers, toggleCollapseCard] = useState([]);
const addCardNumber = (idx, prevState) => {
const arr_cardNum = prevState
!arr_cardNum .includes(idx) && arr_cardNum .push(idx)
return arr_cardNum
}
...
{data.map((obj, idx)=>{
return <div className="card" key={`${idx}_${obj?.lastModifiedOn}`}>
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapseCard(prevState => addCardNumber(idx, prevState))}>Show Json</button>
</div>
</div>
<div className={`card-content ${collapsedCardNumbers.includes(idx) ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>
})}

how to use DOM element in React

I want to do getElementById to give css effect and click to slide function.
how do I use DOM in react? Thank you in advance.
function Auth() {
//this part needs to be fixed
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('body');
signUpButton.addEventListener('click', () =>
container.classList.add('right-panel-active'));
signInButton.addEventListener('click', () =>
container.classList.remove('right-panel-active'));
Here are the classnames that might help you understand my code better.
return (
<div className ="auth">
<div className="body" id="body">
<SignUp className="test" />
<SignIn className="test" />
<div className="slide__body">
<div className="slides">
<div className="slide SignUp__left">
<p>Already have an account?</p>
<button className="slide__btn" id='signUp' > Sign In </button>
</div>
<div className="slide SignIn__right">
<p>Not a Member?</p>
<button className="slide__btn" id='signIn' > Sign Up </button>
</div>
</div>
</div>
</div>
</div>
)
}
I guess the propose to use React is that fact you should interact in the component state.
I suggest you use State in your component and add some according to some interaction
function App() {
const [mode, setMode] = React.useState();
const handleMode = (mode) => {
setMode(mode);
};
const containerClasses =
mode === "signUp" ? "body right-panel-active" : "body";
return (
<div className="auth">
<div className={containerClasses} id="body">
<SignUp className="test" />
<SignIn className="test" />
<div className="slide__body">
<div className="slides">
<div className="slide SignUp__left">
<p>Already have an account?</p>
<button
className="slide__btn"
id="signUp"
onClick={() => handleMode("signIn")}
>
{" "}
Sign In{" "}
</button>
</div>
<div className="slide SignIn__right">
<p>Not a Member?</p>
<button
className="slide__btn"
id="signIn"
onClick={() => handleMode("signUp")}
>
{" "}
Sign Up{" "}
</button>
</div>
</div>
</div>
</div>
</div>
);
}
You should avoid direct modification of the dom in React. React assumes that it is the only piece of code modifying the dom, and so it won't know about any changes you make. This opens up the possibility of bugs where react changes something on the dom that you don't expect, or doesn't change something you do expect. A simple piece of code like yours won't have these bugs, but best to learn the react way now so you don't run into these issues with more complicated code.
The react way to do this is to pass onClick props to the elements that need it, and to have a state variable which controls the class names. For example:
import React, { useState } from 'react';
function Auth() {
const [showPanel, setShowPanel] = useState(false);
return (
<div className="auth">
<div className={showPanel ? "body right-panel-active" : "body"}>
<SignUp className="test" />
<SignIn className="test" />
<div className="slide__body">
<div className="slides">
<div className="slide SignUp__left">
<p>Already have an account?</p>
<button
className="slide__btn"
onClick={() => setShowPanel(false)}
>
Sign In
</button>
</div>
<div className="slide SignIn__right">
<p>Not a Member?</p>
<button
className="slide__btn"
onClick={() => setShowPanel(true)}
>
Sign Up
</button>
</div>
</div>
</div>
</div>
</div>
);
}

How to build a simple chart in React based on data from API response

I would like to build a simple chart in React using Nivo library to represent percentage values from data in API response.
The data from the response looks like this: https://run.mocky.io/v3/7c46c4ce-09c0-4f95-b4e1-84ae10bd24ab
I need to represent this data in a really simple line chart.
So far I have this code in my component:
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import {useParams} from 'react-router-dom';
import Loader from '../Components/Loader';
import { Bar } from "#nivo/bar";
function ArtistDetail() {
const {artist_uuid} = useParams()
const url = `https://run.mocky.io/v3/${artist_uuid}`;
const [artist, setArtist] = useState({
loading: false,
data: null,
error: false
})
let content = null;
useEffect(() => {
setArtist({
loading: true,
data: null,
error: false
})
axios.get(url)
.then(response => {
setArtist({
loading: false,
data: response.data,
error: false
})
})
.catch(() => {
setArtist({
loading: false,
data: null,
error: true
})
})
}, [url])
if(artist.error) {
content = <p>There was an error loading an artist.</p>
}
if(artist.loading) {
content = <p><Loader/></p>
}
if(artist.data) {
content =
<main className="main">
<section className="section section-artist-detail trending claimed">
<div className="page">
<div className="col visual">
<figure>
<img src= {artist.data.data.image}/>
<figcaption>
<button className="btn btn-claim-music-id">Claim music_id</button>
</figcaption>
</figure>
</div>
<div className="col-wrapper">
<div className="col info">
<div className="col-content">
<div className="info-wrapper">
<div className="title-wrapper">
<button className="btn btn-solid border btn-booking-request">Booking Request</button>
<h1 className="title">
{artist.data.data.name}
<div className="tooltip-wrapper">
<span className="profile-claimed">Profile claimed</span>
<div className="tooltip">
<h3>Vote for subgenres</h3>
<p>Don’t agree with the subgenres? Add the ones you think are missing or vote for existing to get yours on top!</p>
<div className="stats-sheet">
{artist.data.data.subgenres.map(subgenre => {
const {name, score} = subgenre;
return (
<div className="row" key={name, score}>
<h5>{name}</h5>
<div className="graph-line">
<span className="line" style= {{width: score + '%'}}>{score}%</span>
</div>
</div>
);
})}
</div>
<p>
<button className="btn btn-shadow">Vote now</button>
</p>
</div>
</div>
<span className="trending-icon">Trending</span>
</h1>
</div>
<div className="row">
<button className="btn btn-save long">Follow</button>
<button className="btn btn-share">
Share
<span>Link copied to clipboard</span>
</button>
</div>
<div className="row">
<label>Origin</label>
<a className="btn btn-filter-tag">{artist.data.data.country.name}</a>
</div>
<div className="row">
<label>Genre</label>
<span className="btn btn-filter-tag">{artist.data.data.genre.name}</span>
</div>
<div className="row">
<label>Subgenres</label>
{artist.data.data.subgenres.map(subgenre => {
const {name} = subgenre;
return (
<span key={name} className="btn btn-filter-tag">{name}</span>
);
})}
<div className="tooltip-wrapper">
<button className="btn btn-add">Add subgenre</button>
<div className="tooltip">
<h3>Vote for subgenres</h3>
<p>Don’t agree with the subgenres? Add the ones you think are missing or vote for existing to get yours on top!</p>
<div className="stats-sheet">
{artist.data.data.subgenres.map(subgenre => {
const {name, score} = subgenre;
return (
<div className="row" key={name, score}>
<h5>{name}</h5>
<div className="graph-line">
<span className="line" style= {{width: score + '%'}}>{score}%</span>
</div>
</div>
);
})}
</div>
<p>
<button className="btn btn-shadow">Vote now</button>
</p>
</div>
</div>
</div>
</div>
<div className="footer-detail">
<ul className="social-list">
{artist.data.data.social_links.map(item => {
const {channel, link} = item;
return (
<li key={channel, link}>
<a href= {link} className= {`btn social-icon ${channel}`}>{channel}</a>
</li>
);
})}
</ul>
<div className="tooltip-wrapper">
<button className="btn btn-add">Add links</button>
<div className="tooltip">
<h3>Got more info?</h3>
<p>Add Place's links so everyone can see their social media highlights.</p>
<p>
<button className="btn btn-shadow">Add links</button>
</p>
</div>
</div>
</div>
</div>
</div>
<div className="col stats">
<div className="col-content">
<Bar
width={600}
height={400}
margin={{ top: 60, right: 80, bottom: 60, left: 80 }}
data={artist.data.data.popularity}
indexBy="city"
keys={["percentage"]}
labelTextColor="inherit:darker(1.4)"
enableGridX={false}
layout="horizontal"
maxValue={10}
axisTop={null}
axisRight={null}
axisBottom={null}
axisLeft={null}
enableGridX={false}
enableGridY={false}
isInteractive={false}
/>
<div className="stats-sheet">
<label>Most popular in</label>
{artist.data.data.popularity.map(popular => {
const {city} = popular;
return (
<div className="row" key={city}>
<h5>{city}</h5>
<div className="graph-line">
<span className="line" style={{width: 47 + '%'}}>47%</span>
</div>
</div>
);
})}
</div>
</div>
</div>
</div>
<button className="btn btn-scroll-down">Scroll down</button>
</div>
</section>
</main>
}
return (
<div>
{content}
</div>
)
}
export default ArtistDetail;
I have no idea how to display the percentage data inside this div:
<div className="graph-line">
<span className="line" style={{ width: 47 + "%" }}>
47%
</span>
</div>;
It looks like this
For the chart I used the code from here
Good work!
Based on Nivo documentation, I'd try with this
<ResponsiveBar
data={data.popularity}
keys={[ 'city', 'percentage' ]}
maxValue={100}
...
>
..setting maxValue in or to 100 for percentages. Passing data.popularity or artist.data.data.popularity to data attribute and setting up appropriate keys.
{artist.data.data.popularity.map(popular => {
const {city} = popular;
Here might be the problem - destructure both 'city' and 'percentage' from 'popular'.
const { city, percentage } = popular
then
<span>{percentage}%</span>
Looking at the design instead of Nivo you can actually use simple css .Below is the code in which I have used flex to achieve that.
CodeSandbox Link
<div className="App">
<h1>Most Popular in</h1>
{popularity.map((popular) => (
<div>
<div>{popular.city}</div>
<div className="linear-graph">
<div
style={{
background: "black",
flex: popular.percentage
}}
/>
<div
style={{
background: "#c5c5c56b",
flex: 10 - popular.percentage
}}
/>
</div>
</div>
))}
</div>
and the css for that
.App {
font-family: sans-serif;
color: black;
}
.linear-graph {
width: 200px;
display: flex;
position: relative;
height: 6px;
margin-bottom: 10px;
}
Cheers

setState doesn't update immediately, alternative way?

I have a modify-button that displays a modal component according to the value of the state property "modalVisible", in other terms the modify-button trigger an event handler which update the state property but since setState is asynchronous, the modal doesn't display properly (sometimes it shows sometimes not)
Is there an alternative to show the modal immediately after clicking modify button in react ?
here is my code i have 4 Components :
The first is Todo component which is used to display the 2 other components: DisplayTasks component (to do list) and the DisplayCompletedTasks (tasks completed),
The fourth is Modal component (just an input text to change the name of the task) which is displayed when clicking on the button modify-button
First component file TaskManagements.js
import React from 'react'
import {DisplayTasks} from './DisplayTasks'
import DisplayCompletedTasks from './DisplayCompletedTasks'
export class Todo extends React.Component{
constructor(props){
super(props);
this.state={
task: '',
tasks: [],
completedTasks: [],
inputVisible: false,
completedVisible: false,
modalVisible: false,
buttonClicked: ''
};
}
toggleInputDisplay = ()=>{
this.setState(state=>({inputVisible: !state.inputVisible}));
}
handleChange = (event)=>{
// Handle input checkboxes that handle completed tasks (the alternative is to use event.target.type==="checkboxes")
if(event.target.name==="choosed"){
//document.querySelector("input[value='" + event.target.value + "']").style.background-color = ""
let arr = this.state.tasks;
arr[event.target.value].checked = !arr[event.target.value].checked;
this.setState({tasks: arr});
}
// Handle the text input storing the text within the task state property
else if(event.target.type==="text"){
this.setState({task: event.target.value});
}
}
addTask = (event)=>{
const arr = this.state.tasks;
arr.push({task: this.state.task, checked: false});
this.setState(state=>({tasks: arr, task: ''}));
}
removeTask = (event)=>{
const arr = this.state.tasks;
arr.splice(event.target.id,1);
this.setState(state=>({tasks: arr}));
}
modifyTask = (event)=>{
this.setState({modalVisible: true});
}
handleParam = (event)=>{
const name = event.target.name;
let arr = this.state.tasks;
arr.forEach(task=>(task.checked = false));
this.setState(state=>({completedVisible: !state.completedVisible, buttonClicked: name,
tasks: arr}));
console.log(this.state.tasks);
}
handleChoosedTasks = (event)=>{
//const inputVar = document.querySelectorAll("[value][name='completed']:checked");
this.setState(state=>({tasks: state.tasks.filter(task=>(!task.checked)), completedVisible: false}));
if(this.state.buttonClicked === 'complete'){
const completedTasks = this.state.tasks.filter(task=>(task.checked));
this.setState(state=>({completedTasks: state.completedTasks.concat(completedTasks)}));
console.log('completed:' + this.state.completedTasks);
}
}
render(){
console.log(this.state.tasks);
return(
<div className="h-100">
<button className="mt-4 btn btn-outline-primary" onClick={this.toggleInputDisplay}>Add Task</button>
<div className="mt-5 ">{!this.state.inputVisible ? '' : (
<div className="mb-4">
<input className="mr-1"type="text" value={this.state.task} onChange={this.handleChange}/>
<button className="btn btn-outline-secondary mr-1" onClick={this.addTask}>Add</button>
<button className="btn btn-outline-secondary" onClick={this.toggleInputDisplay}>Cancel</button>
</div>
)
}
<div className="row p-0 col-6 mx-auto ">
<span style={{"paddingLeft": "14%"}} className=" mb-0 ml-0 col-10 ">Tasks</span>
<button id="complete" name="complete" style={{"fontSize": "14px"}} className="btn btn-success col p-0" onClick={this.handleParam}>
complete</button>
<button id="remove" name="remove" style={{"fontSize": "14px","marginLeft":"5px"}} className="btn btn-danger col p-0" onClick={this.handleParam}>
remove</button>
</div>
<DisplayTasks tasks={this.state.tasks} removeTask={this.removeTask}
completedVisible={this.state.completedVisible} handleChange={this.handleChange}
handleChoosedTasks={this.handleChoosedTasks} modifyTask={this.modifyTask} modalVisible={this.state.modalVisible}/>
<span className=" mb-0 ">Completed</span>
<DisplayCompletedTasks completedTasks={this.state.completedTasks}/>
</div>
</div>
);
}
}
second file DisplayTasks.js
import React from 'react'
import ModifiedModal from './ModifiedModal.js'
import './DisplayTasks.css'
export class DisplayTasks extends React.Component{
render(){
return(
<div id="tasks" style={{"height": "40vh"}} className="mt-2 mb-5 col-6 border border-primary mx-auto ">
{!this.props.modalVisible? '' : <ModifiedModal />}
<div style={{"height": "87%"}} className=" col-12 overflow-auto">{!this.props.tasks.length ? '' : this.props.tasks.map((task,index)=>
(
<div key={`task-${index}`} className="mt-3 mr-0 d-flex p-0 w-100 border">
<div id="parent-task" style={!task.checked ? {...this.style}: {...this.style,"backgroundColor":"yellow"}} className="col-12 ml-0 p-0 d-flex">{!this.props.completedVisible ? ''
: (<label id="c-customized" className="border">
<input name="choosed" type="checkbox" value={index}
onChange={this.props.handleChange}/>
<svg width="30" height="30">
<g>
<circle className="c-b" cx="15" cy="15" r="14" stroke="magenta"/>
<polyline className="c-m" points="6,14 12,20 23,9"/>
</g>
</svg>
</label>)}
<strong className="ml-0 col-11 d-inline-block align-self-center">
{task.task}
</strong>
<button id="modify-button" className="btn btn-primary btn-circle mr-1"><i value={index} className="fas fa-pencil-alt"
onClick={this.props.modifyTask}></i></button>
</div>
</div>
)
)
}
</div>
{!this.props.completedVisible ? ''
: <button id="choosed-confirmed" className="d-flex btn btn-success" onClick={this.props.handleChoosedTasks}>
<span className="mx-auto align-self-center">Ok</span></button>}
</div>
)
}
}
The fourth is the Modal
import React from 'react'
export default function ModifiedModal(props){
console.log("modifiedModal");
return <div className="Modal d-flex ">
<label>
<button id="x-button"></button>
<span>Modify the Task</span>
<input type="text" />
</label>
</div>
}
Use callback of setState like :
this.setState({ variable : updatedValue }, () => {
after update works here...
}
);

ReactJS - Access key of container div on click?

Here is the code that I'm working on right now.
How can I access the key that I have on the container div? Right now I'm just trying to console.log it but ultimately, I need to pass the key to an action so I can make a call to an API.
Thanks for any advice.
I want to access the key on the container div
renderRecipes() {
return _.map(this.props.recipes, recipe => {
return (
<div className="card" style={cardStyle} key={recipe.idMeal}>
<img className="card-img-top" src={recipe.strMealThumb} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{recipe.strMeal}</h5>
<button className="btn btn-outline-primary" onClick={this.viewRecipe}>
View Recipe Details
</button>
</div>
</div>
)
})
}
render() {
console.log(this.props.recipes);
return (
<div>
<h2>Main Ingredient Search Page</h2>
<SearchField />
<div className="d-flex flex-row flex-wrap">
{this.renderRecipes()}
</div>
</div>
);
}
}
You can do it pretty easily with an anonymous function:
<button className="btn btn-outline-primary" onClick={() => this.viewRecipe(recipe.mealId)}>
View Recipe Details
</button>
But the best way would be to extract the recipe into it's own component. Then it's nicely encapsulated and doesn't re-render onclick references.
class Recipe extends Component {
onViewDetails = () => {
this.props.onItemClick(this.props.id);
}
render() {
const {
name,
thumbnail
} = this.props;
return (
<div className="card" style={cardStyle}>
<img className="card-img-top" src={thumbnail} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{name}</h5>
<button className="btn btn-outline-primary" onClick={this.onViewDetails}>
View Recipe Details
</button>
</div>
</div>
)
}
}
--
return _.map(this.props.recipes, recipe => (
<Recipe
key={recipe.idMeal}
id={recipe.idMeal}
thumbnail={recipe.strMealThumb}
name={recipe.strMeal}
onItemClick={this.viewRecipe}
/>
);
I think you could do something like this
renderRecipes() {
return this.props.recipes.map(recipe => {
return (
<div className="card" style={cardStyle} key={recipe.idMeal}>
<img className="card-img-top" src={recipe.strMealThumb} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{recipe.strMeal}</h5>
<button className="btn btn-outline-primary" onClick={() => this.viewRecipe(recipe.idMeal)}>
View Recipe Details
</button>
</div>
</div>
)
})
}
Now, in the onClick function you'll receive the key!
I think you can define your viewRecipe method in this way:
viewRecipe = recipe => e => console.log(recipe)
viewRecipe will be a function that receives a recipe as parameter and returns another function which will be used for the onClick method:
<button className="btn btn-outline-primary" onClick={this.viewRecipe(recipe)}>
Or you can use also the techniques described in the docs which are the following:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Categories