I am relatively new to React and want to render input forms on click of a button. The function called in button's onClick works for stuff like console.log() but does not render the HTML elements. I have absolutely no clue as to why is this happening. I am using function component.
Below is the code snippet that is concerned with the problem.
const UserAppointment = () => {
function renderHtml () {
return(
<div>
<h1>I want this to render on click</h1>
</div>
)
}
return (
<div>
<button onClick={renderHtml}>Render Input forms</button>
<br /><br /><br />
<button onClick={()=> { dispatch(logout()) }}>Logout</button>
</div>
)
}
export default UserAppointment ;
I suggest you should use state to save and render html:
const UserAppointment = () => {
const [html, setHtml] = useState(null);
function renderHtml () {
return(
<div>
<h1>I want this to render on click</h1>
</div>
)
}
return (
<div>
{html}
<button onClick={(() => setHtml(renderHtml()))}>Render Input forms</button>
<br /><br /><br />
<button onClick={() => { dispatch(logout()) }}>Logout</button>
</div>
)
}
Instead of a renderHtml function, have a boolean state. When clicked, toggle the boolean, and conditionally return the JSX when true:
const App = () => {
const [show, setShow] = React.useState(false);
return (
<div>
<button onClick={() => setShow(!show)}>Render Input forms</button>
<br /><br /><br />
<button onClick={()=> { dispatch(logout()) }}>Logout</button>
{
!show ? null : (
<div>
<h1>I want this to render on click</h1>
</div>
)
}
</div>
)
};
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class="react"></div>
When you use event handlers such as onClick(), React doesn't return any HTML back from the function that you pass in.
Like other commenters said, you need to use React state to manage when your div is shown and when it is hidden.
First set the state since you are using functional component.
const [Heading, setHeading] = useState("")
Then use your onClick event and pass a function to it.
<button onClick={renderHtml}>Render Input forms</button>
Set your state to the heading inside renderHtml function.
const renderHtml =()=> {
setHeading("I want this to render on click")
}
Display your heading in h1 in return.
<h1>{Heading}</h1>
Full code:
const [Heading, setHeading] = useState("")
const renderHtml =()=> {
setHeading("I want this to render on click")
}
return (
<div>
<h1>{Heading}</h1>
<button onClick={renderHtml}>Render Input forms</button>
<br /><br /><br />
<button onClick={() => { dispatch(logout()) }}>Logout</button>
</div>
)
}
Related
My code below:
I am learning ReactJS. Trying to change the background colour of the button on mouse hover.
I know css:hover is the easiest approach. But doing this implementation to learn.
It works fine if I check the 'hover' value using if else condition. But it gives the error "TypeError
Cannot assign to read only property 'backgroundColor' of object '#'" when I try to set the background colour inside the onMouseEnter and onMouseLeave event handler functions.
What is the read-only property here? I have not made it const. Is it read-only by default? How do I override it?
import React, { useState } from "react";
function App() {
let [ hover, setState] = useState(false);
let buttonStyle = {
backgroundColor:''
}
function hoverActive(){
setState(true);
buttonStyle.backgroundColor='black';
}
function hoverInactive(){
setState(false);
buttonStyle.backgroundColor='';
}
if(hover){
//buttonStyle.backgroundColor='black';
}
else{
//buttonStyle.backgroundColor='';
}
return (
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button style={buttonStyle} onMouseEnter={hoverActive} onMouseLeave={hoverInactive}>Submit</button>
</div>
);
}
export default App;
Few ways to achieve what you want:
Using useState hook
The issue you have now in your code is buttonStyle not being a state and React just ignores the changes you make to that variable.
function App() {
let [hover, setState] = React.useState(false);
function hoverActive() {
setState(true);
}
function hoverInactive() {
setState(false);
}
return (
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button
style={{
backgroundColor: hover ? "black" : "",
color: hover ? "white" : "black"
}}
onMouseEnter={hoverActive}
onMouseLeave={hoverInactive}
>
Submit
</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Using React refs
You can achieve it using a React ref (using useRef hook for your function component):
function App() {
const buttonRef = React.useRef(null);
function hoverActive() {
buttonRef.current.style.backgroundColor = "black";
buttonRef.current.style.color = "white";
}
function hoverInactive() {
buttonRef.current.style.color = "black";
buttonRef.current.style.backgroundColor = "";
}
return (
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button
ref={buttonRef}
onMouseEnter={hoverActive}
onMouseLeave={hoverInactive}
>
Submit
</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Using CSS
function App() {
return (
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button id="my-button">Submit</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
#my-button:hover {
background-color: black;
color: white;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
It has to do with how object works in javascript.
Refer.. Cannot assign to read only property 'name' of object '[object Object]'
You can take Reference of the object and use State or Ref to update the Background color.
import React, { useState } from "react";
function App() {
let [hover, setState] = useState(false);
let buttonStyle = {
backgroundColor: "",
};
const [ButtonStyle, setButtonStyle] = useState(buttonStyle);
function hoverActive() {
setState(true);
const data = { ...buttonStyle, backgroundColor: "green" };
setButtonStyle(data);
}
function hoverInactive() {
setState(false);
const data = { ...buttonStyle, backgroundColor: "" };
setButtonStyle(data);
}
return (
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button
style={ButtonStyle}
onMouseEnter={hoverActive}
onMouseLeave={hoverInactive}
>
Submit
</button>
</div>
);
}
export default App;
buttonStyle does not cause the component to be re-rendered as a result the value cannot be updated or manipulated. A good approach would be the useState hook and update the state as needed
const [buttonStyle, setButtonStyle] = useState({ backgroundColor: '' })
const handleHover = () => {
setState(!hover);
if (hover) {
setButtonStyle({ ...buttonStyle, backgroundColor: '#fff' });
} else {
setButtonStyle({ ...buttonStyle, backgroundColor: 'red' });
}
};
<div className="container">
<h1>Hello</h1>
<input type="text" placeholder="What's your name?" />
<button
style={buttonStyle}
onMouseEnter={handleHover}
onMouseLeave={handleHover}
>
Submit
</button>
</div>
I'm using the spread operator as its standard practice when setting object state. This does not mutate the original state. Best practice to name your setState based on what they do, e.g setButtonStyle, setHoveredOn
I want to make multiple copies of Form2 React Component with click event, but the code not working as I want, I am new in react so can anybody help me.
const Comform = () => {
const Form2 = () => {
return(
<div className="card" id='form-card2'>
<input className="form-check-input" type="checkbox" value="" id="options-check" onClick={Optionscheck} />
</div>
);
}
const Replica = () {
<Form2/>
}
return(
<button type="button" className="btn btn-success" onClick={Replica}>Add</button>
);
}
Keep a state as the replica counter and render the number of items you want using Array.from and Array.prototype.map.
Try like this:
const Form2 = () => {
return (
<div className="card" id="form-card2">
<input
className="form-check-input"
type="checkbox"
value=""
id="options-check"
// onClick={Optionscheck}
/>
abcd
</div>
);
};
const Replica = () => {
const [replicaCount, setReplicaCount] = React.useState(0);
return (
<div>
<button
type="button"
className="btn btn-success"
onClick={() => setReplicaCount((prev) => prev + 1)}
>
Add
</button>
{Array.from({ length: replicaCount }).map((_, index) => (
<Form2 key={index}/>
))}
</div>
);
};
ReactDOM.render(<Replica />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Summary
You would have to create a handler for the replica button and a state that tracks how often the button was clicked, so that you are able to render as much form items as the button was clicked.
Example
import { useState } from "react";
import "./styles.css";
const FormItem = () => (
<div className="formItem">
<label>Check me</label>
<input type="checkbox" />
</div>
);
const ReplicaButton = ({ addFormItem }) => (
<button onClick={addFormItem}>Add more</button>
);
export default function Form() {
const [formCount, setFormCount] = useState(1);
const addFormItem = () => setFormCount(formCount + 1);
return (
<div>
<form className="formius">
{Array(formCount)
.fill(null)
.map(() => (
<FormItem />
))}
</form>
<ReplicaButton addFormItem={addFormItem} />
</div>
);
}
I have this reusable component where I would like to pass a value through that if true: a button is returned and if the value is false: the button doesn't render. I can't figure out how to do this using reusable components. The boolean variable I want to use is displayButton where if it is true, then the button is rendered and if it is false then the button is not rendered.
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
//if display button = true, display this button, if false, button is not displayed
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
<h4>{purchased}</h4>
</div>
);
};
export default Test;
Any help would very appreciated!
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
{displayButton &&
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
}
<h4>{purchased}</h4>
</div>
);
};
export default Test;
if displayButton has the value of true it will render the button otherwise not
This will work.
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
{ displayButton &&
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
}
<h4>{purchased}</h4>
</div>
);
};
export default Test;
You can create a ShowHide component which can be utilized for conditional-rendering instead of having logical operators in every JSX where you need to conditionally render.
// create a ShowHide component
const ShowHide = ({show,children} ) => show && children
// your Test component with the button wrapped in ShowHide
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData card col-6 m-3">
<h5>{name}</h5>
<p>Cost: {value}</p>
<ShowHide show={displayButton}>
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
</ShowHide>
<h4>{purchased}</h4>
</div>
);
};
const root = document.getElementById('root');
ReactDOM.render(
<Test name="My Card"
value="250,000"
onClick={() => alert('clicked')}
purchased="Yes!"
displayButton={false}
/>,
root
)
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Good Luck...
hello I have a few buttons and I want to scroll to them when clicked.
const [active, setActive] = useState(0);
useEffect(() => {
// I´m not using useRef. is there other way to automatically scroll to the element and stop at 0 0 of the page?
})
<div style={{height: '10000px'}} />
<button onClick={() setActive(1)}>button 1</button>
<button onClick={() setActive(2)}>button 2</button>
<button onClick={() setActive(3)}>button 3</button>
<div style={{height: '10000px'}} />
as you can see there´s a lot of scroll caused by those 2 divs. the idea is to scroll down and when you reach the buttons and click the one you need. the page scrolls to that button leaving it in the top of the page
image 1: scroll in random position
image 2: when you click on button 1
image 3: when you click on button 2
image 4: when you click on button 3
For scrolling react view to top there is a simple function.
use window.scrollTo(0, 0);
inside your code try this.
<button onClick={()=> window.scrollTo(0, 0) }>button 1</button>
edited:
I could come up with this solution after you edited your question.
import React, { useRef } from "react";
export default function App() {
const button1Ref = useRef();
const button2Ref = useRef();
const button3Ref = useRef();
const handleScroll = ref => {
window.scrollTo({
behavior: "smooth",
top: ref.current.offsetTop
});
};
return (
<div className="App">
<div style={{ height: "10000px" }} />
<div>
<button ref={button1Ref} onClick={() => handleScroll(button1Ref)}>
button 1
</button>
</div>
<div>
<button ref={button2Ref} onClick={() => handleScroll(button2Ref)}>
button 2
</button>
</div>
<div>
<button ref={button3Ref} onClick={() => handleScroll(button3Ref)}>
button 3
</button>
</div>
<div style={{ height: "10000px" }} />
</div>
);
}
Please try it out. Let me know if this is what you asked for.
Edited after question asked in comment for using single component with Ref and using that component in multiple numbers:
If you want to use a single component for button then try this,
import React, { useRef } from "react";
export default function App() {
return (
<div className="App">
<div style={{ height: "10000px" }} />
<MyButton>button 1</MyButton>
<MyButton>button 2</MyButton>
<MyButton>button 3</MyButton>
<div style={{ height: "10000px" }} />
</div>
);
}
const MyButton = props => {
const buttonRef = useRef();
const handleScroll = () => {
window.scrollTo({
behavior: "smooth",
top: buttonRef.current.offsetTop
});
};
return (
<div>
<button ref={buttonRef} onClick={handleScroll}>
{props.children}
</button>
</div>
);
};
Here you want to use an event handler.
const handleClick = (e) => {
// scrollIntoView logic and set state
}
<div onClick={handleClick}/>
//action
const goDown= (e) => {
const anchor = document.querySelector('#some-id')
anchor.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
// click to scroll
<Link onClick={goDown}>Choose Health</Link>
//element you want to scroll to
<div id='some-id'>
</div>
I have a simple component that displays data onClick event on a button. Here is my component:
import React, { Component } from 'react';
import './cardCheck.css';
class CardCheck extends Component {
constructor(props) {
super(props);
this.state = { showMessage: false };
}
_showMessage = bool => {
this.setState({
showMessage: bool
});
};
render() {
return (
<div>
<div className="newsletter-container">
<h1>Enter the ID of your card:</h1>
<div className="center">
<input type="number" />
<input type="submit" value="Check" onClick={this._showMessage.bind(null, true)} />
</div>
<div className="results" />
{this.state.showMessage && (
<div>
hello world!
<button onClick={this._showMessage.bind(null, false)}>hide</button>
</div>
)}
</div>
<h1>Offers:</h1>
</div>
);
}
}
export default CardCheck;
The code works, but I have this error in my console:
JSX props should not use .bind()
I read about it and changed my function to arrow ones like this:
import React, { Component } from 'react';
import './cardCheck.css';
class CardCheck extends Component {
constructor(props) {
super(props);
this.state = { showMessage: false };
}
_showMessage = bool => () => {
this.setState({
showMessage: bool
});
};
render() {
return (
<div>
<div className="newsletter-container">
<h1>Enter the ID of your card:</h1>
<div className="center">
<input type="number" />
<input type="submit" value="Check" onClick={this._showMessage()} />
</div>
<div className="results" />
{this.state.showMessage && (
<div>
hello world!
<button onClick={this._showMessage()}>hide</button>
</div>
)}
</div>
<h1>Offers:</h1>
</div>
);
}
}
export default CardCheck;
The error is gone, but my code does not work now. What is the correct way to do this with arrow functions and still make it work?
Either binding or using arrow function is not suggested since those functions will be recreated in every render. This is why you see those warnings. Instead of binding or invoking with an arrow function use it with reference and change your function a little bit.
_showMessage = () =>
this.setState( prevState => ( {
showMessage: !prevState.showMessage,
}) );
Instead of using a boolean, we are changing showMessage value by using its previous value. Here, we are using setState with a function to use previous state since setState itself is asynchronous.
And in your element you will use this function with its reference.
<input type="submit" value="Check" onClick={this._showMessage} />
Working example.
class CardCheck extends React.Component {
constructor(props) {
super(props);
this.state = { showMessage: false };
}
_showMessage = () =>
this.setState( prevState => ( {
showMessage: !prevState.showMessage,
}) );
render() {
return (
<div>
<div className="newsletter-container">
<h1>Enter the ID of your card:</h1>
<div className="center">
<input type="number" />
<input type="submit" value="Check" onClick={this._showMessage} />
</div>
<div className="results" />
{this.state.showMessage && (
<div>
hello world!
<button onClick={this._showMessage}>hide</button>
</div>
)}
</div>
<h1>Offers:</h1>
</div>
);
}
}
ReactDOM.render(
<CardCheck />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
<input type="submit" value="Check" onClick={this._showMessage()} />
You are invoking the _showMessage function by having the () in the onClick handler. You just want to pass the reference to the function, i.e. without ()
<input type="submit" value="Check" onClick={this._showMessage} />