I have button & i'm getting button text in console.log. But now i want to this button text in <h2> tag but this is not working whats wrong with it?
My Code:-
const Forms = () => {
const handleClick =( event) => {
const theText = event.target.textContent;
console.log(theText);
};
return (
<div>
<h2>{theText}</h2>
<button onClick={handleClick}>click</button>
</div>
);
};
ReactDOM.render(<Forms />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Comment this line <h2>{theText}</h2> to get button text in console.log.
Thanks for your efforts!
The variable theText is scoped to the {} block. Since you want to change something in the view using this variable, it should be in your state.
Try using the useState hook. Now everytime your theText changes there is a rerender and the view gets updated.
const Forms = () => {
const [theText,setTheText] = useState("default");
const handleClick =( event) => {
const theText = event.target.textContent;
setTheText(theText);
};
return (
<div>
<h2>{theText}</h2>
<button onClick={handleClick}>click</button>
</div>
);
};
Notice how I have the same variable name theText but there will be no conflicts. This is a major advantage of using const/let they are block scoped.
import {useState} from 'react'
const Forms = () => {
const [text,setText] = useState();
const handleClick =( event) => {
const theText = event.target.textContent;
setText(theText);
console.log(theText);
};
return (
<div>
<h2>{text}</h2>
<button onClick={handleClick}>click</button>
</div>
);
};
This can be achieved with state.
This is how you can save to state and access
const Form = () => {
const [selectedText, setSelectedText] = React.useState("");
const handleClick = (event) => {
const theText = event.target.textContent;
setSelectedText(theText);
};
return (
<div>
<h2>{selectedText}</h2>
<button onClick={handleClick}>click</button>
</div>
);
}
The basic workflow of React is that a component 1) initially renders 2) the state of the component changes, 3) the component re-renders based on that new state.
So you need to introduce state to your component so that when you click the button the state of the text changes.
const { useState } = React;
function Forms() {
// Initially set the state to an empty string
const [text, setText] = useState('');
function handleClick(event) {
// Now grab the textContent from the button
// and set the state. The component will immidiately
// re-render, and the H2 will be set to `text`
const { textContent } = event.target;
setText(textContent);
};
return (
<div>
<h2>{text}</h2>
<button onClick={handleClick}>click</button>
</div>
);
};
// Render it
ReactDOM.render(
<Forms />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Related
I have found this error while trying to build another React app. So I am only asking the main issue here in a demo app, I might not be able to change any rendering methods here since it is not the actual project.
Issue in simplified form -> I was building a app where two count will be shown and a + button will be there next to that count value. When the button is clicked the count should be increased by 1. Unfortunately when I try to click on the button the value is increasing only the first time. After that the value is not even changing. But when I am implementing the same using Class component its working as expected.
Functional Component
import React, { useState } from "react";
function Page(props) {
const [count, setCount] = useState(0);
const [content, setContent] = useState({
button: (value) => {
return <button onClick={() => handlePlus(value)}>+</button>;
},
});
function handlePlus(value) {
console.log("value=", value);
const data = count + 1;
setCount((count) => data);
}
return (
<div>
<span>Functional Component Count = {count}</span>
{content.button(10)} // 10 will be replaced with another variable
</div>
);
}
export default Page;
Class Component
import React, { Component } from "react";
class PageClass extends Component {
state = {
count: 0,
content: {
button: (value) => {
return (
<button onClick={() => this.handlePlus(value)}>+</button>
);
},
},
};
handlePlus = (value) => {
console.log("value=", value);
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<span>Class Component Count = {this.state.count}</span>
{this.state.content.button(10)} // 10 will be replaced with another variable
</div>
);
}
}
export default PageClass;
App.js
import "./App.css";
import Page from "./components/Page";
import PageClass from "./components/PageClass";
function App() {
return (
<div className="App">
<Page />
<PageClass />
</div>
);
}
export default App;
However, If I replace that content state variable with normal const variable type and it is working as expected.
Below is working when I am not using any hooks to render the button.
But this is not helpful for my case.
const content = {
content: () => {
console.log(count);
return <button onClick={() => handlePlus(value)}>+</button>;
},
};
I was trying to create some re-usable components and hence I wanted to have that function in state variable which return button tag, so that I can implements some other logic there.
The value will be missing since you're passing a hard-coded 10.
I'd recommend simplifying the handlePlus to just:
setCount(c => c + 1);
Then set the onclick like so:
<button onClick={handlePlus}>+</button>
And your code will work as expected as you can see in this snippet:
const { useState } = React;
const Example = () => {
const [count, setCount] = useState(0);
const [content, setContent] = useState({
content: (value) => {
return <button onClick={handlePlus}>+</button>;
},
});
function handlePlus(value) {
setCount(c => c + 1);
}
return (
<div>
<span>{count}</span>
{content.content(10)}
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
That said, I'd recommend removing the button from the hook, and just render it yourself:
const { useState } = React;
const Example = () => {
const [count, setCount] = useState(0);
function handlePlus(value) {
setCount(c => c + 1);
}
return (
<div>
<span>{count}</span>
<button onClick={handlePlus}>+</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
See React documentation about the c => c + 1 syntax
I have a variable that I don't want to bind to state in React. So I declared it as let with initial value as null. Later with event I set its value in parent and then pass it to child. But in child its value is getting null. Not sure what mistake I am making. Below is the code.
function Parent() {
const[showChild, setShowChild] = useState(false);
let data = null;
const setData = () => {
data = 'Test';
setShowChild(true);
console.log('function called');
};
return (
<>
<button onClick={setData}>
Click Me
</button>
{showChild && <Child data={data} />}
</>
);
}
function Child({data}) {
console.log('data ' + data);
return (
<>
<h2>
{data}
</h2>
</>
);
}
ReactDOM.render(
<Parent />,
document.getElementById('mountNode'),
);
If you want to persist state you have to use useState as you did in the first line. so instead of manually let data ... and const setData you should have something like the following:
const [data, setData] = useState(null)
You sould use useState, whenever the state changes in parent, child will be render again.
I changed your example a little bit to show you what happen exactly, child just shows the value that parent has sent.
const {useState} = React;
const Parent=()=> {
const[showChild, setShowChild] = useState(false);
const[data, setData] = useState(0);
//let data = null;
const handleClick = () => {
setData((prev=>prev+1));
setShowChild(true);
console.log('function called');
};
return (
<div>
<button onClick={handleClick}>
Click Me
</button>
{showChild && <Child data={data} />}
</div>
);
}
const Child=({data})=> {
console.log('data ' + data);
return (
<div>
<h2>
{data}
</h2>
</div>
);
}
ReactDOM.render( <Parent/> ,
document.getElementById("mountNode")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="mountNode"></div>
when I changed the disabled of button from true to false, it messed my onClick, why is that, and how to solve it?
const Component = () => {
const refrence = React.useRef(null)
setTimeout(() => {
refrence.current.disabled = false
}, 1000);
const handleClick = () => console.log('clicked')
return (
<div>
<button onClick={handleClick} ref={refrence} disabled>click me</button>
</div>
)
}
ReactDOM.render(
<Component />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><div id="root"></div>
Issue
The issue here is that the React ref is mutating the DOM, but React isn't made aware of this and so Component isn't rerendered with a working button allowing the onClick event to go through. This is the main reason why direct DOM manipulations are considered anti-pattern in React.
Additionally, you are setting a timeout to occur every render, though this would have minimal effect it's still unnecessary and would be considered an unintentional side-effect.
Solution
Use component state and update state in a mounting useEffect hook to trigger a rerender.
const Component = () => {
const [isDisabled, setIsDisabled] = useState(true);
useEffect(() => {
setTimeout(() => {
setIsDisabled(false);
}, 1000);
}, []);
const handleClick = () => console.log('clicked');
return (
<div>
<button onClick={handleClick} disabled={isDisabled}>click me</button>
</div>
)
}
const Component = () => {
const [isDisabled, setIsDisabled] = React.useState(true);
React.useEffect(() => {
setTimeout(() => {
setIsDisabled(false);
}, 1000);
}, []);
const handleClick = () => console.log('clicked');
return (
<div>
<button onClick={handleClick} disabled={isDisabled}>click me</button>
</div>
)
};
ReactDOM.render(
<Component />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
this is my first post and I am a beginner with JS and react so go easy. My issue is that I am not getting a number type returned where I want it... it occurs in the CurrentNumber component. Instead it is an [object Object] reference. I am assuming there is something wrong with my types/prop validation. Code posted below.(p.s. I also tried to use the number prop type in the validation) no dice.
import React, {useState,} from "react";
import PropTypes from 'prop-types';
const CurrentNumber = props => (
<p>
{props.countnumber}
</p>
);
const Applet = () => {
// Declaring a state variable called "count"
const [count, setCount] = useState(0);
//########################## Utils & Functions #########################
const incrementCount = props => {
setCount(props.countnumber+=1)
}
const resetCount = () => {
setCount(0);
}
// ######################### View in Browser ####################
return (
<div className={"game"}>
<div className={"header"}>
This is a header.
</div>
<div className={"body"}>
<button onClick={incrementCount}
countnumber = {count}
>
Click me
</button>
<CurrentNumber
countnumber={count}
/>
</div>
<p>
<button onClick = {resetCount}
countnumber = {count}
>
Reset
</button>
</p>
</div>
);
}
///////////// PROP VALIDATIONS ////////////////////
CurrentNumber.propTypes = {
countnumber: PropTypes.string,
}
////////////////////////////////////////////////////////////////////////////
export default Applet;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
const incrementCount = props => {
setCount(props.countnumber+=1)
}
should be
const incrementCount = () => {
setCount(c => c+1)
}
or alternatively
const incrementCount = () => {
setCount(count+1)
}
I am using useref to display dynamic content
let refValue= useRef(null);
When there is new data, the data is getting overlapped with old data which has to be cleared, but the old data is still retaining with ref, how do i overcome this and clear the old data
Since refs do not notify when it changes you can use a callback.
Documentation: useRef Documentation
Here is an example using a callback.
Bear in mind that you probably don't need to pass the dependency in the callback, in the example I did it to force the change.
const {
useState,
useEffect,
useCallback,
} = React;
const CompWithRef = ({title}) => {
const [myRef, setRef] = useState(null);
const myRefCallback = useCallback(node => {
if (node !== null) {
setRef(title);
}
}, [title]);
return (
<div>
<p ref={myRefCallback}>Prop title = {title} </p>
<p>When your ref changes update state, ref state value = {myRef}</p>
</div>)
};
const Example = () => {
const [title, setTitle] = useState('initial title');
setTimeout(function(){ setTitle("Title is updated"); }, 3000);
return (
<CompWithRef title={title}/>
);
};
ReactDOM.render( <Example /> ,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>