Cannot add our own react element onclick - javascript

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>

Related

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

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

Alternative to document in next.js

I'm still new to learning next.js, but the problem is, I don't understand. How do we call an element from the written html because I want to do like the code written below?
HTML
<div class="container_title">
<div class="main_title">
<h1> Title <span>( Global )</span></h1>
<div class="button_main_title">
<button class="Tap_1 button" >Tap_1 </button>
<button class="Tap_2 button">Tap_2</button>
<button class="Tap_3 button">Tap_3</button>
<button class="Tap_4 button">Tap_4</button>
<button class="Tap_5 button">Tap_5</button>
</div>
</div>
</div>
javascript
const main_title = document.querySelector(".main_title");
const button_main_title = document.querySelectorAll(".main_title button");
(() => {
main_title.addEventListener('click', event => {
if(event.target.classList.contains("button")){
for(i=0;i<button_main_title.length;i++) button_main_title[i].classList.remove("active");
event.target.classList.add("active")
}
})
})();
const Firsr_BTN = document.querySelector(".button_main_title .button:first-child");
Firsr_BTN.click();
NextJS is a framework which is based on React, which is based on Javascript. However, the only way that I know to select an element is to use a React hook called useRef. Let me give you an example.
import React, { useRef } from 'react'
const YourComponent = () => {
const myHeading = useRef()
console.log('heading', myHeading)
return (
<div>
<h1 ref={myHeading}>Heading</h1>
</div>
)
}
Now you have your h1 as myHeading and you can modify it the way you want. Always check your console for what's the element object looks like and how to edit it.

How to store the return value of a function inside a variable in reactJS

my code:
import "./styles.css";
export default function App() {
getUserValue = (e) => {
let value = e.target.value;
console.log(value)
return value
}
let userInputValue = getUserValue
return (
<div>
<div>
<h4>Sign Up</h4>
</div>
<div>
<div>
<p>Username</p>
<input onChange = {getUserValue}/>
</div>
<div >
<p>Password</p>
<input/>
</div>
</div>
<div>
<button onClick = {console.log(userInputValue)}>Submit</button>
</div>
<div>
<button>
Close
</button>
</div>
</div>
);
}
code sandbox: https://codesandbox.io/s/dazzling-sea-my5qm?file=/src/App.js:0-720
I'm trying to store the returned value of "getUserValue" function to "userInputValue" variable so I can log the input the user made and use it in different functions. I can't get it to work though, when I console log the variable hoping to get the returned result after I made an input I don't get anything, as if the button doesn't work.
I'm trying to store the returned value of "getUserValue" function to "userInputValue" variable so I can log the input the user made and use it in different functions.
You'd do that by making the input state in your component. In a function component like yours, that means using the useState hook (or various libraries like Redux that have alternative ways of doing it).
Here's a simple example, but you can find lots of more complex ones by searching:
const { useState } = React;
function Example() {
// Call the hook to get the current value and to
// get a setter function to change it. The default
// value ("" in this example) is only used the first
// time you call the hook in this component's lifecycle
const [userInput, setUserInput] = useState("");
// Handle changes in the input by setting state.
// Note that this function is recreated every time your
// component function is called to update. That's mostly
// fine, but there are times you might want to optimize
// that.
const onChange = (event) => {
setUserInput(event.currentTarget.value);
};
// Handle clicks on the button that show' the current input.
const onClick = () => {
console.log(`The current userInput is "${userInput}"`);
};
// Return the rendering information for React
return <div>
{/* Provide the value and hook the "change" (really "input") event */}
<input type="text" value={userInput} onChange={onChange} />
<input type="button" onClick={onClick} value="Show Current" />
</div>;
}
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>

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>
}

Passing html element value to composeWithTracker in React

This Meteor code uses React. When user fills in an input box with id myVal, click a button. The input box value gets sent to the server via a method, the server updates the collection vehicles.
It then needs to take that input from user and use that as query to collection.findOne in myfile.jsx. It failed to pass the user input myVal from html input element.
How can it be done? Thanks
// -------------------- myfile.jsx -------------------
const renderWhenData = ( cars ) => {
if ( cars ) {
return <span>{ cars.description }</span>;
}
};
const Info = ( { cars } ) => (
<p>{ renderWhenData( cars ) }</p>
);
const composer = (props, onData) => {
const subscription = Meteor.subscribe('vehicles');
if (subscription.ready()) {
let myVal = document.getElementById('myVal').value;
console.log(myVal); // <------------------ nothing is printed out
const cars = Vehicles.findOne({name: myVal});
onData(null, {cars});
}
};
const Container = composeWithTracker(composer)(Info);
ReactDOM.render(<Container />, document.getElementById('react-info'));
// --------------------- events.js -----------------------
document.getElementById('startButton').addEventListener('click', () => {
const myVal = document.getElementById('myVal').value;
Meteor.call('startInfo', myVal); // <---------- updates server collection
});
<!--main.html-->
<head>
</head>
<body>
<form action="submit">
<input type="text" id="myVal">
<div id="react-info"></div>
</form>
<footer>
<button id="startButton">START</button>
</footer>
</body>
The question is a bit academic. There are better ways to handle this in React. But, since you are using Meteor, this can be done with some Tracker operations.
First define a tracker dependency:
export const textboxDep = new Tracker.Dependency;
Whenever the textbox value changes, trigger the changed event.
textboxDep.changed();
Within the composer, use
textboxDep.depend();
If the composer is written well, when the tracker dependency is invalidated, the whole functional container component runs again. And you should see the value of the textbox there.
Right now, when the value of the textbox is changed, since it is not reactive, the container does not re-render itself.

Categories

Resources