Using data from one component in another in Reactjs - javascript

I made a counting app that when you click you level and get gold, but how do use the data in another component? For example, I want to use this.state.max in another component.
Sorry, I'm quite new to React
import React, {Component} from 'react';
import '../App.css';
import darkalien from '../assets/darkgray__0000_idle_1.png';
import darkalien2 from '../assets/darkgray__0033_attack_3.png';
import darkalien3 from '../assets/darkgray__0039_fire_5.png';
var style = {
color: 'black',
fontSize: 20
};
var style2 ={
color: '#daa520',
fontSize: 20
}
export default class Home extends Component{
constructor(props) {
super(props);
this.state = {
i: 0,
j: 1,
k: 0,
max: 10,
maxf: 2,
maxi: 10
}
}
onClick(e) {
e.preventDefault();
var level = this.state.j;
this.setState({i: this.state.i + 1});
this.setState({k: this.state.k + 1});
if(this.state.i >= this.state.max){
this.setState({j: this.state.j + 1});
this.setState({i: this.state.i});
this.setState({k: this.state.k});
if(this.state.j === this.state.maxf){
this.setState({maxf: this.state.maxf + 1});
this.setState({max: this.state.max + 10});
}
this.setState({i: this.state.i = 0});
}
}
render(){
return(
<header>
<div className="container" id="maincontent" tabIndex="-1">
<div className="row">
<div className="col-lg-12">
<div className="intro-text">
<p className="name" style={style} id="demo3">Level {this.state.j}</p>
<p className="name" id="demo4" style={style}>Points: {this.state.k}</p>
<p className="name" style={style2} id="demo5">Gold: {this.state.max}</p>
<img id="picture" className="img-responsive" src={darkalien} alt="alien-img" onClick={this.onClick.bind(this)} height="150" width="150"/>
<progress id="demo2" value={this.state.i} max={this.state.max}></progress>
<h1 className="name">Click me!</h1>
<hr className="glyphicon glyphicon-star-empty"></hr>
<span className="skills">Gain Experience ★ Get Coins ★ Purchase Armor</span>
</div>
</div>
</div>
</div>
</header>
);
}
}
I want to use the this.state.max in my store component:
import React, {Component} from 'react';
import blaster from '../assets/blaster_1.png';
import blaster2 from '../assets/blaster_3.png';
import alienSuit from '../assets/predatormask__0000_idle_1.png';
import alienHair from
'../assets/alien_predator_mask_0007_hair_profile.png';
import Home from '../components/Home';
export default class Store extends Component{
render(){
return(
<section id="portfolio">
<div className="container">
<div className="row">
<div className="col-lg-12">
<h3>Armor and Weapon Store<span> **Gold:{this.state.j}** </span></h3>
</div>
</div>
<div className="row text-center">
<div className="col-md-3 col-sm-6 hero-feature">
<div className="thumbnail">
<img src={blaster} alt=""/>
<div className="caption">
<h3>Reggae Blaster</h3>
<p>
Buy Now! More Info
</p>
</div>
</div>
</div>
</div>
</div>
</section>
);
}
}

React's architecture is specifically designed to not have cross-component dependencies. If you had a lot of those dependencies you would find yourself quickly in a 'hairball' that would make code maintenance very difficult.
However if you want to manage an App state in a controlled way I would recommend to consider using a state container (especially if your app gets more complex). You could look into Redux for example and potentially also use the server / database to store more long time data. Here is an article explaining a different categorization of states.
And of course - Here's the link to the must read me of Redux and the basic tutorial, which should help with your use case.

You could retrieve the data held in your state by creating a function in the class that returns that data. For example
export default class Home extends Component{
constructor(props) {
super(props);
this.state = {
i: 0,
j: 1,
k: 0,
max: 10,
maxf: 2,
maxi: 10
}
}
getMax(){
return this.state.max
}
//Rest of your code...
}
You would then call getMax by defining a new instance of Home with
var home = new Home
then call the getMax function wherever you need your this.state.max
var max = home.getMax()
However as the other answers have said I would recommend looking at another form of state management, my personal favorite being Redux.

Related

React not re-rendering the component on setState even though state is being updated

So Here's my code.
import React, {Component} from 'react';
import Typist from 'react-typist';
import SvgComponent from './mapComponent';
import {stateData} from '../shared/exampleData';
class Home extends Component{
constructor(props){
super(props);
this.state={
isHovered:false,
active:"347",
res_today:"29",
new_today:"16",
hoveredState:null
}
}
changeOnHover = (stateCode) =>{
console.log("HERE is whats inside ",stateCode,stateData[stateCode]);
this.setState({
hoveredState:stateData[stateCode],
isHovered:true
},()=>{
console.log("mouse in",this.state)
});
}
mouseOut = () =>{
this.setState({
isHovered:!this.state.isHovered
},()=>console.log("After Mouse Out",this.state))
}
render(){
var isHovered = this.state.isHovered;
return(
<div className="container-fluid">
<div className="row">
<div className="col-12 col-md-7 large-screen-text">
<Typist>
<div className="top-text">
<br/>
<h1>781 Districts. 26 States. 1 Stop for all Complaints</h1>
</div>
<div className="mid-text">
<br/>
<h1 className="">Register Your Complaints</h1>
</div>
<div className="bottom-text">
<br/>
<span>
{isHovered ?
<h1>Active: {this.state.hoveredState.active}
<small>(+{this.state.hoveredState.new_today})</small>
</h1>
:
<h1>Active: {this.state.active}
<small>(+{this.state.new_today})</small>
</h1>}
<br />
<h1>Resolved Today: {this.state.res_today}</h1>
</span>
</div>
</Typist>
<div class="pie-chart">
</div>
</div>
<div className="col-12 col-md-5">
<div>
<SvgComponent changeOnHover={this.changeOnHover} mouseOut={this.mouseOut}/>
</div>
</div>
</div>
</div>
)
}
}
I'm making use of SVG Component to change state information on hover over the SVG figure.
Here is a portion of what the SVGComponent has :
function SvgComponent(props) {
return (
<svg
xmlnsMapsvg="http://mapsvg.com"
xmlnsDc="http://purl.org/dc/elements/1.1/"
xmlnsCc="http://creativecommons.org/ns#"
xmlnsRdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlnsSvg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="svg2"
viewBox="2 0 700 700"
>
<defs
id="defs42" />
<a onMouseOver={()=>props.changeOnHover("IN-AN")} onMouseLeave={()=>props.mouseOut()}>
<path
id="IN-AN"
title="Andaman and Nicobar Islands"
d="m 537.188,685.44148 -0.041,0.4695 0.768,0.30627 0.104,2.47542 1.258,1.84675 -0.71,-0.0232
0.661,0.93295 -0.574,0.18739 -0.437,0.94503 0.103,1.88201 -0.409,0.42617 -0.663,-0.49065,..
....,-0.62565 z" />
</a>
.
.
.
</svg>);
}
Now, According to the above mentioned code, it should work such that when mouse moves over the figure developed using the path tag in svg, the number displayed in active within Home must update. But it is not happening. I can see that the state is getting updated but there is not re-rendering happening.
Here is what stateData imported from exampleData contains:
export const stateData ={
"IN-AN": {
active:"10",
new_today:"68",
res_today:"17"
},
"IN-AP":{
active:"14",
new_today:"45",
res_today:"78",
},
"IN-TN":{
active:"19",
new_today:"87",
res_today:"76",
},
"IN-KA":{
active:"69",
new_today:"69",
res_today:"69",
},
"IN-KL":{
active:"12",
new_today:"13",
res_today:"14",
}
}
Edit 1: It was not updating because of the Typist Component I was using for animation. After I removed it, it worked fine.

React map adding background color special elements

I use map but I have one problem I am trying to set the background of a certain element inside the map, in my case it is "item .title" I want my element to look like this https://ibb.co/ccJzD6g as you can see in the picture background color " 100% "which I specifically set in the console for but in fact if I set" background: orange "for the sidebar_list class, then the color will be applied to all elements including the rest , https://ibb.co/ZBTX3hd and if I set the background for the titleName class it looks like this https://ibb.co/84RKBBw but I want it to look like this https://ibb.co/ccJzD6g how do i solve this problem?
Lesson.jsx
import React from 'react';
import less from "./css/lesson.module.css";
import "./css/betaLesson.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { Navbar } from "../../../Navbar/Navbar";
export class Lessons extends React.Component {
constructor(props) {
super(props);
this.state = {
indexDescription: 0,
}
}
render() {
const listLessons = this.props.lesson.map((item, index) => {
return (
<li key={index} className={less.sidebar_list} onClick={() => {
this.setState({ indexDescription: index })
}}>
<div>
<FontAwesomeIcon className={less.item_icon} icon={item.iconName} />
</div>
<div style={{background: "orange"}} className={less.titleName}>
<p>{item.title}</p>
</div>
<div className={less.titleName}>
<p>{item.titleName}</p>
</div>
</li>
);
});
return (
<>
<div className="abc">
<Navbar color="blue" bg="tomato" centerFlexNavbarContainer="flex"
navbarSearchPage="Search" navbarHomePage="Home" centerHeadlineNavbarColumn="center" />
<div className={less.wrapper}>
<div>
<div className={less.sidebar}>
<div>
<ul>
{listLessons}
</ul>
</div>
</div>
</div>
<div className={less.main_content}>
<div className={less.main_inside_content}>
<div className={less.header}>
<div>
<h2>JavaScript JSON Reference</h2>
</div>
</div>
<div className={less.info}>
<div className={less.description}>
<p>
{
this.props.lesson[this.state.indexDescription]["description"]
}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
}
}
First question answer: Create a new component with its own attributes separately and map/passdown the properties to the component.
Here's an example: https://codesandbox.io/s/objective-hopper-2st8g?file=/src/Lesson.js

React Component not displaying different text / information despite being given unique objects as passed props

I am currently creating a progressive web app with React, HTML, JS, and CSS for learning purposes and have run into an issue where my ExercisePanel components are displaying the exact same information despite being given 2 different objects to pull information from. The ExercisePanel is a stylized button that displays an image and the name of the exercise, and it accurately updates with the different objects. The problem stems from my custom Modal that I made to display the information, as it always displays the information of the first component listed in the App.js file. I have also cut down on some of the Strings for the sake of readability. The files below are what I believe are causing the problem, however I have been unable to figure out the cause. I apologize if the code is messy, I am a beginner with these tools. (Order is App.js then ExercisePanel.js then Modal.jsx)
// Import React and Component
import React, { Component } from 'react';
// Import CSS from App.css
import './App.css';
import Exercise from './js/classes/Exercise.js';
// Import the Today component to be used below
import ExercisePanel from './Components/ExercisePanel.js'
class App extends Component {
render() {
var test = new Exercise("Curl Ups", "10-30", "30 - 90", "A curl up (or sit up) ...", "Medium", "https://img.icons8.com/ios-glyphs/96/000000/sit-ups.png");
var test2 = new Exercise("TEST2", "ur", "2", "sda", "sad", "");
return (
<div className="">
<div className="topheader">
<header className="container">
<nav className="navbar">
<div className="navbar-brand">
<span className="navbar-item"><font class="topheader">Let's Move!</font></span>
</div>
</nav>
</header>
</div>
<section className="results--section">
<div className="container">
<h1>Let's Move is a Website ...</h1>
</div>
<div className="results--section__inner">
<ExercisePanel exercise={test}/>
<ExercisePanel exercise={test2}/>
</div>
</section>
</div>
);
}
}
export default App;
import React from 'react';
import ExerciseButton from './ExerciseButton';
import Modal from './Modal'
let ExercisePanel = (props) => {
return (
<div>
<ExerciseButton image={props.exercise.image} id={props.exercise.name} onClick={handleClick}>{props.exercise.name}</ExerciseButton>
<Modal desc={props.exercise.desc} clickEvent={handleClick} cal={props.exercise.calories} time={props.exercise.estTime} name={props.exercise.name} diff={props.exercise.difficulty}/>
</div>
);
}
function handleClick() {
document.querySelector('.modal').classList.toggle('modal--hidden');
}
export default ExercisePanel;
import React from 'react';
import "./ModalStyle.css"
var Modal = ({name, desc, cal, time, diff, clickEvent}) => {
return (
<div className="modal modal--hidden">
<div style={{backgroundColor: "#beb", padding: "2rem 4rem", maxWidth: "50%", borderRadius: "10px"}}>
<div className="close-button">
<button style={{border: "none", background: "none", cursor: "pointer"}} onClick={clickEvent}>X</button>
</div>
<div className="modal--header">
<span style={{fontWeight: "bold"}}>{name}</span>
</div>
<p>
{desc}
</p>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/ios-filled/50/000000/fire-element.png" alt="calorieImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Calories: " + cal}</span>
</div>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/pastel-glyph/50/000000/clock.png" alt="clockImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Recommended Time: " + time}</span>
</div>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/android/40/000000/flex-biceps.png" alt="difficultyImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Difficulty: " + diff}</span>
</div>
<div className="modal--infotext">
<span>*Values given by estimated calories were from a moderately intense workout for a healthy individual.</span>
</div>
</div>
</div>
);
}
export default Modal;
I suspect it is because when you click the button it executes document.querySelector('.modal').classList.toggle('modal--hidden'); which toggles the modal--hidden class on all modals, so no matter which button you click both modals are opened and you only see the one that is on top.
You probably want to add an open prop to your Modal component and use that prop to conditionally add the modal--hidden class to the root modal div.

Update component with data from parent in React

In my react app I have this child component that inherits data from its parent. However, it does not update the page with new data from the child component when a relevant anchor link is clicked.
Here's my build - https://suite-search-lk.surge.sh/result/369523
From the link above if you click on a suggested card h1 element it just updates the URL with the id but does not update the page with the relevant card data from that id.
Any idea how I can fix this? Do I have to force the component to re-update?
Parent component (Card Wrapper)
class CardWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
stories: []
};
}
componentDidMount() {
axios
.get(API)
// .then(response => console.log(response))
// get our stories array, check it and then change state to contain our stories
.then(data => {
let stories;
if (data.data.stories && data.data.stories) {
if (Array.isArray(data.data.stories)) {
stories = data.data.stories;
} else {
stories = [data.data.stories];
}
} else {
stories = [];
}
this.setState({
stories: stories
});
});
}
render() {
return (
<CardWrapperDiv>
<div className="headingWrapper">
<div className="heading"> Suggested for you</div>
</div>
<Cards>
{this.state.stories.map(story => {
return (
<Card
title={story.content.title}
img={story.content.img}
description={story.content.description}
deadline={story.content.deadline_date}
tags={story.content.tags}
key={story.id}
id={story.id}
/>
);
})}
</Cards>
</CardWrapperDiv>
);
}
}
export default CardWrapper;
Child component
class Card extends React.Component {
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
Sorry it seems I have figured this out using the following post - Can you force a React component to rerender without calling setState?
Although I'm not exactly sure if it's the best way to go about it.
Essentially I used an OnClick listener to run a function and forces a re-render of the entire component.
Hope this can help someone else :)
class Card extends React.Component {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`} onClick={this.handleButtonClick}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
U have to use ur child component as a pure component. PureComponent Update when ur props change.
class Card extends React.PureComponent {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
.....
.....
</CardDiv>
);
}
}
export default Card;

How do I properly pass function props on another component with React.Component?

I am introducing my self in es6+, I have a hard time trying to pass a function props to another component.
This is my code:
class ProductList extends React.Component {
constructor(props) {
super(props);
this.onVote = this.handleProductUpVote.bind(this);
}
handleProductUpVote(productId) {
console.log(productId +" was upvoted.")
}
render() {
const products = Data.map((product) => {
return (
<Product
key={'product-'+product.id}
id={product.id}
title={product.title}
description={product.description}
url={product.url}
votes={product.votes}
submitter_avatar_url={product.submitter_avatar_url}
product_image_url={product.product_image_url}
onVote={this.handleProductUpVote}
/>
);
});
return (
<div className="ui items">
{products}
</div>
);
}
}
I want to pass the function onVote in this component(Product)
class Product extends React.Component {
handleUpVote() {
this.props.onVote(this.props.id).bind(this) /* the error is here, I am trying
to pass the id props, and invoke the onVote prop here */
}
render() {
return (
<div className="item">
<div className="image">
<img src={this.props.product_image_url} />
</div>
<div className="middle aligned content">
<div className="description">
<a onClick={this.handleUpVote}>
<i className="large caret up icon"/>
</a>
{this.props.votes}
</div>
<div className="description">
<a href={this.props.url}>
{this.props.title}
</a>
</div>
<div className="extra">
<span> Submitted by: </span>
<img
className="ui avatar image"
src={this.props.submitter_avatar_url}
/>
</div>
</div>
</div>
);
}
}
I have no problem with other props here. I am trying to invoke the function on handleUpVote, I used bind with it, but I can't make it work. Help?
You have to use bounded handleProductUpVote method when you pass it to Product component.
As you can see in constructor, you already bound it and assigned to this.onVote property.
There are 2 solutions:
You should use onVote={this.onVote} in render method.
Change the name of property onVote in constructor to this.handleProductUpVote. And you end up with this.handleProductUpVote = this.handleProductUpVote.bind(this) and leave assignment in render method (i.e. onVote={this.handleProductUpVote})
More info at http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
Update:
And update your Product class:
class Product extends React.Component {
constructor(props) {
super(props);
this.handleUpVote = this.handleUpVote.bind(this);
}
handleUpVote() {
this.props.onVote(this.props.id)
}
// the render method
}
Remove the bind in handleUpVote() in your Product component and just invoke it like this.props.onVote(this.props.id);

Categories