can't append h1 element to parent div in React? - javascript

i'm creating a simple react website that's supposed to do some calculations and find out Joules of my input values after the calculations...right now the input values are already preset but i will remove the value="" from my <input> later.
here is the .JSX component file that's the issue...one of the components.
import React, { Component } from 'react';
import Atom_icon from './cartridges.png';
class Joule_calc extends Component {
render(){
return (
<div className='Joule_div'>
<h3 style={{color:"white", textAlign:"center"}}>JOULE CALCULATOR</h3>
<label className='lab1'>WEIGHT=/GRAMS</label><br></br>
<input className='weight_inp' type='text' value="2" />
<label className='lab2'>SPEED=M/S</label><br></br>
<input className='speed_inp' type='text' value="5" />
<button className='count_button' onClick={this.Create_response}>CALCULATE</button>
<h1 className='Result_joule'></h1>
</div>
)
}
Create_response(){
console.log("creating response...")
let sum = document.createElement("h1")
sum.className = 'Result_joule'
sum.textContent = "678"
let div_panel = document.getElementsByClassName("Joule_div")
div_panel.append('Result_joule')
}
Returned_values(){
let weight_val = document.getElementsByClassName("weight_inp")[0].value;
let speed_val = document.getElementsByClassName("speed_inp")[0].value;
let final_calculation = weight_val * speed_val
return final_calculation
}
}
export default Joule_calc
so when i run my code i get
Uncaught TypeError: div_panel.append is not a function
at Create_response (Joule_calc_window.jsx:31:1)
i don't get why i can't append my new element to the div. it says it's not a function so what's the solution then? i'm new to React and web so probably it's just a noobie thing.
also i tried directly creating a h1 inside the 'Joule_div' like this.
<h1 className='Result_joule'>{"((try returning here from one of these methods))"}</h1>
but that of course failed as well. So would appreciate some help to get what's going on. i'm trying to add a number after the button click that's in h1 and in future going to be a returned number after calculating together the input values in a method.i imagine that something like
MyMethod(){
value = values calculated
return value
}
and later grab it with this.MyMethod
example
<h1>{this.MyMethod}</h1>
this is a example that of course didn't work otherwise i wouldn't be here but at least gives you a clue on what i'm trying to do.
Thank you.

You don't leverage the full power of react. You can write UI with only js world thanks to JSX. State changes triggering UI update.
I may miss some specificaiton, but fundamental code goes like the below. You should start with function component.
// Function component
const Joule_calc = () =>{
// React hooks, useState
const [weight, setWeight] = useState(0)
const [speed, setSpeed] = useState(0)
const [result,setResult] = useState(0)
const handleCalculate = () =>{
setResult(weight*speed)
}
return (
<div className="Joule_div">
<h3 style={{ color: 'white', textAlign: 'center' }}>JOULE CALCULATOR</h3>
<label className="lab1">WEIGHT=/GRAMS</label>
<br></br>
<input className="weight_inp" type="text" value={weight} onChange={(e)=>setWeight(parseFloat(e.target.value))} />
<label className="lab2">SPEED=M/S</label>
<br></br>
<input className="speed_inp" type="text" value={speed} onChange={(e)=>setSpeed(parseFloat(e.target.value))} />
<button className="count_button" onClick={handleCalculate}>
CALCULATE
</button>
<h1 className='Result_joule'>{result}</h1>
</div>
)
}
export default Joule_calc;

div_panel is an collection of array which contains the classname ["Joule_div"]. so first access that value by using indexing . and you should append a node only and your node is "sum" not 'Result_joule' and you should not use textcontent attribute because you will be gonna definitely change the value of your result as user's input value
Create_response(){
console.log("creating response...")
let sum = document.createElement("h1")
sum.className = 'Result_joule'
//sum.textContent = "678"
let div_panel = document.getElementsByClassName("Joule_div")
div_panel[0].append('sum')
}
if any problem persists , comment below

Related

how can I make div tags as much as number in state(react.js)

I'm developing with React.js and below is a simplified version of my component. As you can see, when I click the button state(number) would get a number. And here is what I want, make div tags as much as a number in state(number) in the form tag(which its class name is 'b').
Could you tell me how to make this possible? Thanks for reading. Your help will be appreciated.
//state
const[number,setNumber] = useState('')
//function
const appendChilddiv =(e)=>{
e.preventDefault()
setNumber('')
}
<div>
<form className="a" onSubmit={appendChilddiv}>
<input
value={number}
onChange={(e)=>setNumber(e.target.value)}
type="number"/>
<button type="submit">submit</button>
</form>
<div>
<form className="b">
</form>
</div>
</div>
I've created a codesandbox which includes the following code, previously you were storing the value as a string, it'd be best to store it as number so you can use that to map out, which I do via the Array() constructor (this creates an array of a fixed length, in this case the size of the divCount state - when we update the state by changing the input value this creates a re-render and thats why the mapping is updated with the new value)
import "./styles.css";
import * as React from "react";
export default function App() {
//state
const [divCount, setDivCount] = React.useState(0);
//function
const appendChilddiv = (e) => {
e.preventDefault();
// Submit your form info etc.
setDivCount(0);
};
return (
<div>
<form className="a" onSubmit={appendChilddiv}>
<input
value={divCount}
onChange={(e) => setDivCount(Number(e.target.value))}
type="number"
/>
<button type="submit">submit</button>
</form>
<div>
<form className="b">
{Array(divCount)
.fill(0)
.map((x, idx) => (
<div key={idx}>Div: {idx + 1}</div>
))}
</form>
</div>
</div>
);
}
You can map over an array whose length is same as that entered in input & create divs (if number entered is valid):
{!isNaN(number) &&
parseInt(number, 10) > 0 &&
Array(parseInt(number, 10))
.fill(0)
.map((_, idx) => <div key={idx}>Hey!</div>)
}
isNaN checks is number is valid
parseInt(number, 10) converts string into number,
Array(n) creates a new array with n elements (all empty) (try console logging Array(5)) - so you need to fill it
.fill(n) fill the array (make each element n)
and map is used to render different elements from existing things
So, in this way, you can achieve the mentioned result.
Here's a link to working Code Sandbox for your reference
You can do the following.
First thing it does is creates a new array of some length number.
Next, it fills that array with undefined, because creating new arrays like this doesn't really create an array of that length.
Lastly, we map over this array, we use the index as our key.
We return an empty div for each item in the array.
Note, using an index as a key isn't the best idea. In general it should be something as unique as possible. If you have data you can use that is unique, then you should use that as a key.
return new Array(number).fill(undefined).map((_, key) => <div key={key}></div>);
You can even do it without 'Submit' button. See the codesandbox link and the code snippet below:
import "./styles.css";
import * as React from 'react';
import { useState } from 'react';
export default function App() {
const [divTags, setDivTags] = useState([])
const appendChilddiv = (e) => {
const numberAsString = e.target.value;
let numberDivTags;
if (numberAsString.length === 0) {
numberDivTags = 0
} else {
numberDivTags = parseInt(numberAsString, 10)
}
setDivTags([...Array(numberDivTags)])
console.log(divTags)
}
return (
<>
<form className="a">
<input type="number" onChange={appendChilddiv}/>
</form>
<form className="b">
{divTags.map((e, i) => {
return <p key={i}>Div number {i}</p>
})}
</form>
</>
);
}

Cannot add our own react element onclick

I am working on a tasklist page. The main page has a form in which the user would add the task and click on the add task button and the corresponding task would be appended to the "todo-task" div. I am using my own created react element (Do laundry is just for example) which returns a checkbox followed by the text passed as prop. In the following code I am trying to append at the end of our todo-task div but it is showing me some error. Is my approach right? If not what approach should I take?
import React,{useState} from 'react'
import './Tasklist.css'
import Button from 'react-bootstrap/Button';
import AddBoxIcon from '#material-ui/icons/AddBox';
import Checkbox from '#material-ui/core/Checkbox';
import Task from './Task.js';
function Tasklist() {
const [task, settask] = useState("")
let pendingTask = document.getElementById('pending-task')
let doneTask = document.getElementById('done-task')
const addTask = (event)=>{
event.preventDefault()
let tmp_text=task.trim()
if(tmp_text==="")return
let task_tmp = document.createElement(<Task text={tmp_text} />);
pendingTask.appendChild(task_tmp);
settask("");
}
const keyDownEvent=(e)=>{
let key=e.key
if(key==='Enter' && !e.shiftKey)addTask(e);
}
return (
<>
<div className="add-task">
<form >
<textarea
type="text"
value={task}
rows={1}
placeholder="Add Task"
onChange={(e)=>settask(e.target.value)}
onKeyDown={keyDownEvent}
/>
<Button variant="outline-primary" onClick={addTask}>
<AddBoxIcon /> Add Task
</Button>
</form>
</div>
<div className="todo-task" id="pending-task">
</div>
<Task text="Enjjoyyyy!!!" />
<hr />
<div className="done-task" id = "done-task">
<ul id="done-task-list">
</ul>
</div>
</>
)
}
export default Tasklist
You're going about this in a fundamentally incorrect way, so it's not a quick fix. Now is the time to take a big step back and start over on your component.
What you're currently trying to do is modify the DOM directly. Don't do that in React. What you should instead be doing is maintaining state.
Instead of trying to directly create an element and add it to the DOM, create a record and update state with that record. This is an entirely separate task than rendering the DOM. The actual rendering is done based on that current state.
Currently in your state you have "a task". But you're trying to build functionality to add more tasks. So really your state should have a list of tasks, and you can add to that list. (Which can be in addition to the single task, of course. You can use useState as many times as you like.)
For example, consider state like this:
const [tasks, setTasks] = useState([]);
Then add a task in your button click handler:
const addTask = (event)=>{
event.preventDefault();
let tmp_text=task.trim();
if(tmp_text==="") return;
setTasks([...tasks, tmp_task]); // <--- here
settask("");
}
This keeps a running array of the tasks being stored.
Then in the rendering, you would .map over those tasks to show them:
<div className="todo-task" id="pending-task">
{tasks.map((t, i) => (
<Task key={i} text={t} />
))}
</div>

Why props alone are being used in called React function component?

I was learning React and I came to a point which created confusion. Everywhere I was using props while writing Function components.
I always use props.profile and it works fine. But in one code component, I had to write
const profiles=props; and it worked fine.
I tried using const profiles=props.profile; and also I tried using inside return in 'Card' function component
{props.profile.avatar_url} but both of them failed
Below is my code which works fine
const Card=(props)=>{
const profiles=props; //This I dont understand
return(
<div>
<div>
<img src={profiles.avatar_url} width="75px" alt="profile pic"/>
</div>
<div>
<div>{profiles.name}</div>
<div>{profiles.company}</div>
</div>
</div>
);
}
const CardList=(props)=>{
return(
<div>
{testDataArr.map(profile=><Card {...profile}/>)}
</div>
);
}
Can someone please help me understand why I can't use const profiles=props.profile?
What are the other ways to achieve the correct result?
Your testDataArr might be this,
testDataArr = [{avatar_url:"",name:"",company:""},{avatar_url:"",name:"",company:""},{avatar_url:"",name:"",company:""}]
Now when you do this,
{testDataArr.map(profile=><Card {...profile}/>)}
here profile = {avatar_url:"",name:"",company:""},
and when you do,
<Card {...profile}/>
is equivalent to,
<Card avatar_url="" name="" company=""/>
In child component, when you do this,
const profiles=props;
here props = {avatar_url:"",name:"",company:""}
So you can access it's values,
props.avatar_url
props.name
props.company
But when you do this,
const profiles=props.profile
profile key is not present in {avatar_url:"",name:"",company:""} object and it fails.
OK. Here is the issue, the props object does not contain a profile attribute, but IT IS the profile attribute. Becouse you are spreading the profile variable when you render the Card element (in the CardList), you basically are writing:
<Card avatarUrl={profile.avatarUrl} comapny={profile.comany} />
Instead, you should do
<Card profile={profile} />
and then in your Card component access the data this way
const Card = (props) => {
const profile = props.profile
}
or even simpler
const Card = ({profile}) => {
return <div>{profile.comany}</div>
}

How to implement an array increment function within JSX code using React.js JavaScript

I'm trying to develop a React program that changes information in a component each time the button "rectForward" or "rectBackward" is pressed. I'm passing the information in the form of an array of objects into my Body component from "importData" as seen below. That data is then converted into each object's indvidual data pieces through the map functions listed directly after render() is called. What I want to happen when the rectForward button is pressed is for the "text1" array value in Column1 to incrament by 1. The same happens when rectBackward is pressed, but I want the value to decrement. My primary difficulty is the syntax. As you can see in the statement onClick={Column1.text1=text1val[++], this was my first attempt at implementing this functionality, but the syntax is definitely incorrect. I was wondering if I could get some help formatting this
import React from "react";
import "./Body.css";
import Column1 from "./Body/Column1/Column1";
import "./Buttons.css";
import Column2 from "./Body/Column2/Column2";
import myData from "./myData";
class Body extends React.Component {
constructor() {
super()
this.state = {
importData: myData
}
}
render() {
var ID = this.state.importData.map(item => item.id)
var text1val = this.state.importData.map(item => item.text1)
var text2val = this.state.importData.map(item => item.text2)
var text3val = this.state.importData.map(item => item.text3)
return(
<div className="mainBody">
<div className="backPain">
<div className="holder">
<Column1 key={ID[0]} text1={text1val[0]}>
</Column1>
<div className="rectHolder">
<div className="rectForward" onClick={Column1.text1=text1val[++]}
<h2>Next</h2>
</div>
<div className="rectBackward">
<h2>Prev</h2>
</div>
</div>
<Column2 key={ID[0]} text2={text2val[0]} text3={text3val[0]}>
</Column2>
</div>
</div>
</div>
)
}
}
export default Body;
Thanks so much!
Simple thing i will do is keep an index in state. Than pass a function to next and prev which takes care of changing this index. and will show the values based on current state.
this.state = {
currentIndex : 0
}
HandleCurrentIndex(type){
if(type === 'inc'){
this.setState({currentIndex: this.state.currentIndex++})
} else {
this.setState({currentIndex: this.state.currnIndex-1 })
}
}
<div className="rectForward" onClick={()=>this.HandleCurrentIndex("inc")}>
<h2>Next</h2>
</div>
<div className="rectBackward" onClick={()=>this.HandleCurrentIndex('dec')}>
<h2>Prev</h2>
</div>
On side note:- This is just and example in product you should take care of index going below zero as well index exceeding limits of your data. which in turn will show undefined values. simple thing you should do is whenever it goes out of limit just reset it to default value ( 0 )

creating elements in React

I don't understand how elements are created in React.
I have some code below where the goal is to create elements on a form submit using a value from a refs - so for every submit in a form, it creates a new <h1> tag with the content of the textbox inside of it. A sample of what I'm trying to do looks like:
...
addHeader(e) {
e.preventDefault();
const newHeader = this.refs.post.value;
var newpost = React.createElement("h1", {
type: "text",
value: newHeader
});
}
...
render() {
return (
<div className="form-section">
{ newPost }
<form onSubmit={this.addHeader.bind(this)}>
<input id="input-post" type="text" placeholder="Post Here" ref="post" />
<input type="submit" value="Submit" />
</form>
<button className="form-section__submit" onClick={this.clearFields.bind(this)}>Clear All</button>
</div>
);
}
Basically my thinking is in my addHeader() function I'm assigning a variable of newPost to the method and calling it within my component. This code is causing 2 errors:
33:9 warning 'newpost' is assigned a value but never used no-unused-vars
49:13 error 'newPost' is not defined no-undef
What I don't understand, is (from what I can see) I am assigning a value to that variable and also using it in the component that I am rendering... along with that, I don't understand this error message. How can something be assigned a value but be undefined at the same time...? Is it because it's in the wrong scope? How do I declare where the new element is rendered specifically in the component?
I read the documentation but it doesn't give a clear answer as to how to control where in the component the new element is rendered.
Made some changes to your code. You're going to want to initialize component state in your constructor. In your addHeader method you will use this.setState to update the state of the component with a new posts value including the value of this.input. I changed your ref on the input an actual ref. You take the element and store on this. Every time you add a new post you will get a new <h1> with the value of the textarea.
...
addHeader(e) {
e.preventDefault();
this.setState((prevState, props) => {
return { posts: [ ...prevState.posts, this.input.value ] };
});
}
...
render() {
const { posts } = this.state;
return (
<div className="form-section">
{ posts.map( text => <h1>{ text }</h1> ) }
<form onSubmit={this.addHeader.bind(this)}>
<input id="input-post" type="text" placeholder="Post Here" ref={ el => this.input = ref } />
<input type="submit" value="Submit" />
</form>
<button className="form-section__submit" onClick={this.clearFields.bind(this)}>Clear All</button>
</div>
);
}
As an aside: Binding functions in the render method of react components will cause a performance hit. There is no need to re-bind the this context of the function on every render. this.clearFields.bind(this) should become this.clearFields and you will need to add this.clearFields = this.clearFields.bind(this) to your constructor. You do not need to bind functions that are not used as callbacks.
You're going to want to do the same thing for this.addHeader.bind(this).

Categories

Resources