React onClick button is not triggering the function - reactjs

I am developing an chrome extension where i need to authentication user but a very simple onClick button which calls a function is not working
this is the simple code where i want to show info on console when button is clicked
import React, { useState } from 'react';
const Login = () => {
const [user, setuser] = useState("");
const handleSubmit = (data) => {
data.preventDefault();
console.log("usernae: ");
console.log("Data: ", data.target);
}
const getInputValue = (event) => {
console.log(event.target.value)
// Select input element and get its value
console.log("I am heresdfg")
// let inputVal = document.getElementsByClassName("usernameInputField")[0].value;
// Display the value
// alert(inputVal);
}
return (
<div
id="login-form">
<p>
<div className='form'>
</div>
<input type="text"
id="username"
name="username"
className='usernameInputField'
value={user}
onChange={(event => setuser(event.target.value))}
placeholder="Username" required />
</p>
<p>
<button onClick={getInputValue} type="button" id="login">button</button>
</p>
</div>
);
};
export default Login;

It seems like you want the input value value inside the event handler if I'm not wrong, you can get it from the state - user as
const getInputValue = (event) => {
console.log(user)
}
as the event would be button's you wouldn't get the value of input from it's event and it is not required too as it's already in the react's state ....
Example:
const {useState} = React;
const App = () => {
const [name, setName] = useState("");
const submitHandler = () => {
console.log(name)
}
return (
<div>
Name: <input type="text" value={name} onChange={(e)=>setName(e.target.value)}/>
<button onClick={submitHandler}>Submit</button>
</div>
);
};
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App/>
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

In the getInputValue function event is pointing to the button.
Change the event.target.value to user if you want to print the text into the console.
Here's the codesandbox.
If you don't want to use the value from useState then you can also check useRef hook which works in a similar way.

Related

TSX Input Value

I am developing a web app using React.JS.
I would like the input to be a default value, but the input can't be uneditable.
I have tried :
let [inputValue, setInputValue] = useState<string>('Value of Input')
return (
<div className = "App">
<input value={inputValue}></input>
</div>
The problem with this is that i can't edit the input.
I think you need onChange on that input, and you can change state with that onChange event
const handleOnChange = (event) => {
setInputValue(event.target.value);
};
and you can add h1 to see what's inside the state
<h1>this is what inputValue state content: {inputValue}</h1>
and the whole code will look like this
import { useState } from "react";
export default function App() {
const [inputValue, setInputValue] = useState("Value of Input");
const handleOnChange = (event) => {
setInputValue(event.target.value);
};
return (
<div className="App">
<h1>this is the content of inputValue state: {inputValue}</h1>
<input onChange={(event) => handleOnChange(event)}></input>
</div>
);
}
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)}></input>

setState on submit and not onChange

I have a form, where I use the input from the input fields to send to a back-end.
For example, I have a variable looking something like this:
const [data, setData] = useState([])
const [inputField, setInputField] = useState()
Then I have a form that looks something like this:
<form onSubmit={fetchData}>
<input type="number" value={value} onChange={(e) => setInputField(e.target.value)} />
<button type="submit">Fetch data</button>
</form>
The fetchData is given by:
function fetchData(e?: any) {
e?.preventDefault();
POST("/api", {
inputField: inputField,
}).then(async (response) => {
const json = await response.json();
setData({
retrievedData: json.retrievedData,
});
});
}
I have other forms as well, where this onChange updating is good, but for some input fields I don't need it do update/re-render before the actual submit button that triggers the form are clicked.
So how do I update the state of the inputField when the button is clicked, instead of now where it updates every time I write a new character in the input field ?
Try this
import {useRef } from "react";
export const Temp = () => {
const inputField = useRef(null);
const onBtnClick = () => {
alert(inputField?.current?.value);
};
return (
<div>
<input type="text" ref={inputField} />
<button type="submit" onClick={onBtnClick}>
Fetch data
</button>
</div>
);
};
You can use useRef hook for that.
const inputNumber = useRef();
<input
ref={inputNumber}
id="number"
placeholder="33xx"
type="number"
/>
Then on button click you can get the value like that
inputNumber.current?.value,
You don't need a state for that and you don't even need a ref. You can get the form values directly from the submit event (event.target.<input name>.value). You will need to add the name property to the <input /> to make it accessible from the event target. Please, find the example below:
function Form() {
const [data, setData] = React.useState();
const onSubmit = (e) => {
e.preventDefault();
const inputField = e.target.inputField.value;
POST("/api", {
inputField: inputField,
}).then(async (response) => {
const json = await response.json();
setData({
retrievedData: json.retrievedData,
});
});
};
return (
<form onSubmit={onSubmit}>
<input type="text" name="inputField" />
<button type="submit">Submit</button>
</form>
);
}
ReactDOM.render(
<Form />,
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>

React.js setState not getting update wiith onclick

This is my sample code, it's very basic i just want to console fname once submit is clicked.
When i pressed first time i get an empty line but when pressed second time the button i get some empty value. I am attaching the screenshot for the console.
I dont want to change my code to a class and use some method to get the value in console.
screenshot for console output
import React,{useState} from 'react'
export const anyComponent = () => {
const [fname, setFname] = useState('')
const submit = (event) =>{
setFname({fname: [event.target.value] })
console.log(fname)
}
return(
<div>
<input name="fname" type="text" placeholder="Enter your First Name" />
<button onClick={submit}>Submit</button>
</div>
)
}
From MDN Docs:
The target property of the Event interface is a reference to the object onto which the event was dispatched.
In your case, event.target would point to the button and not input.
What you need is a reference to the input, you can use useRef hook for it like this
import React, { useState, useRef } from "react";
export default anyComponent = () => {
const inputEl = useRef(null);
const [fname, setFname] = useState("");
const submit = event => {
setFname({ fname: [inputEl.current.value] });
};
console.log(fname);
return (
<div>
<input
name="fname"
ref={inputEl}
type="text"
placeholder="Enter your First Name"
/>
<button onClick={submit}>Submit</button>
</div>
);
};
Also, setState is asynchronous, that's why you wouldn't see the result in the console just after calling setFname. However you'd see the updated fName in console on the next render, that's why I've moved it out of the submit.
Without useRef
Alternatively, you can add onChange handler on input and update the state fname from there
function App(){
const [fname, setFname] = useState("");
const submit = () => {
console.log(fname);
};
const handleChange = ev => {
setFname({ fname: [ev.target.value] });
}
return (
<div>
<input
name="fname"
onChange={handleChange}
type="text"
placeholder="Enter your First Name"
/>
<button onClick={submit}>Submit</button>
</div>
);
};
Your console log should be outside submit method. Or log event.target.value instead fname.

cannot clear form field with functional react hook in reactjs

The code below works fine by submit a post message. now i want to clear the message input form on form submission but cannot get it to work. I have tried the following 3 options but yet no luck.
1.)
function clearState() {
message('');
}
// pass the clear state function on form submission
clearState();
2.) Clear form by referencing the form id
document.getElementById('my_form').reset();
3.) using event target reset
event.target.reset();
here is the full code.
import React, { useState, useRef, useEffect } from "react";
export default function App(props) {
const [message, setMessage] = useState("");
const [messages, setMessages] = useState([]);
const currentDate = new Date();
useEffect(() => {
// fetch content axio or ajax
}, []);
function clearState() {
message('');
}
function handleChange(event) {
setMessage(event.target.value);
}
function handleSubmit(event) {;
event.preventDefault();
const newMessages = messages;
const data = { message: message, date: new Date() };
setMessages(newMessages.concat([data]));
//clear all form field based on form id
clearState();
//document.getElementById('my_form').reset();
//event.target.reset();
}
return (
<React.Fragment>
<div className="chat_container">
{messages.map((m, e) => (
<div key={e}>
<div className="chat_message">
chat: {m.message} ---{m.date.toLocaleTimeString()}
</div>
</div>
))}
</div>
<div className="myFooter">
<form id"my_form" onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={message} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
</React.Fragment>
);
}

how to use form in React as a component

I tried to put a form in a separate reusable component but when used that way I can't type anything into the input. I observed, that after entering one letter (it does not appear in the input box) it seems that React rerender the whole component and the name is updated with the inserted letter.
in the version 2 the same code works correctly.
// the part same for the both versions
const [userdata, setUser] = useState({});
const { name } = userdata
const handleChange = key => event => {
setUser({
...userdata,
[ key ]: event.target.value
});
};
const submitEdit = event => {
event.preventDefault();
handleChange();
};
// VERSION 1. doesn't work
const FormEdit = () => (
<form>
<div className="form-group">
<input onChange={handleChange("name")} type="text"/>
</div>
<button onClick={submitEdit}> Submit </button>
</form>
)
return (
<Layout>
<div>
{name} //<-it shows only one letter
<FormEdit />
</div>
</Layout>
);
// VERSION 2 -> works properly
return (
<Layout>
<div>
{name} //<-the updated name is shown immediately
<form>
<div className="form-group">
<input onChange={handleChange("name")} type="text"/>
</div>
<button onClick={submitEdit}> Submit </button>
</form>
</div>
</Layout>
);
};
export default User;
The issue is directly related to declaring the FormEdit component within the other component. Here's why:
In a functional component, everything declared inside gets destroyed and re-created each render. It's no different than a normal function call. This is what makes React's hooks so special. They keep track of values in between renders and make sure they are re-created with the correct values.
You're declaring the FormEdit component inside a function, which means not only is it re-declared every render, but as a side-effect it also un-mounts and remounts each render as well.
This has a few different effects:
The component's input loses focus every render.
It's impossible for it to maintain its own state.
It's not very performant.
Below is a working example to demonstrate.
const {useState, useEffect} = React;
const Example = () => {
// the part same for the both versions
const [userdata, setUser] = useState({});
const { name } = userdata
const handleChange = (key) => (event) => {
setUser({
...userdata,
[ key ]: event.target.value
});
};
const submitEdit = (event) => {
event.preventDefault();
handleChange();
};
const FormEdit = () => {
useEffect(() => {
console.log('mount');
return () => console.log('unmount');
}, []);
return (
<form>
<div>
<input onChange={handleChange("name")} type="text"/>
</div>
<button onClick={submitEdit}> Submit </button>
</form>
)
}
return (
<div>
{name}
<FormEdit />
</div>
);
}
ReactDOM.render(<Example />, 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>
As for why you only see the first character; You are not giving the input a value, only an onChange. If the component does not unmount, this just makes it an "uncontrolled" component. The input still gets it's value updated, you just can't programatically control it. But, since it is unmounting and re-mounting every render, it loses its last value every time the user types.
Making it a controlled input would fix this:
const {useState, useEffect} = React;
const Example = () => {
// the part same for the both versions
const [userdata, setUser] = useState({});
const { name } = userdata
const handleChange = (key) => (event) => {
setUser({
...userdata,
[ key ]: event.target.value
});
};
const submitEdit = (event) => {
event.preventDefault();
handleChange();
};
const FormEdit = () => {
useEffect(() => {
console.log('mount');
return () => console.log('unmount');
}, []);
return (
<form>
<div>
<input value={name} onChange={handleChange("name")} type="text"/>
// ^ Add this
</div>
<button onClick={submitEdit}> Submit </button>
</form>
)
}
return (
<div>
{name}
<FormEdit />
</div>
);
}
ReactDOM.render(<Example />, 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>
This is a little better, but still not ideal. Now it keeps the value each update, but it still loses focus. Not a very good user experience.
This final solution is to never declare a component within another component.
const {useState, useEffect} = React;
const FormEdit = (props) => {
useEffect(() => {
console.log('mount');
return () => console.log('unmount');
}, []);
return (
<form>
<div>
<input value={props.name} onChange={props.handleChange("name")} type="text"/>
</div>
<button onClick={props.submitEdit}> Submit </button>
</form>
)
}
const Example = () => {
// the part same for the both versions
const [userdata, setUser] = useState({});
const { name } = userdata
const handleChange = (key) => (event) => {
setUser({
...userdata,
[ key ]: event.target.value
});
};
const submitEdit = (event) => {
event.preventDefault();
handleChange();
};
return (
<div>
{name}
<FormEdit name={name} handleChange={handleChange} submitEdit={submitEdit} />
</div>
);
}
ReactDOM.render(<Example />, 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>
Now it only mounts once, keeps focus, and updates as expected.
You would have to pass your form handlers to the child component as props so that the lifted state can be manipulated from the child.
// Parent Component
...
const [userdata, setUser] = useState({});
const { name } = userdata
const handleChange = key => event => {
...
};
const submitEdit = event => {
...
};
return (
<Layout>
<div>
{name}
<FormEdit handleChange={handleChange} submitEdit={submitEdit}/>
</div>
</Layout>
);
and then in the child:
// Child Component
const FormEdit = (props) => (
<form>
<div className="form-group">
<input onChange={props.handleChange("name")} type="text"/>
</div>
<button onClick={props.submitEdit}> Submit </button>
</form>
)
Your FormEdit component which is inside the App component is causing the entire App component to re-render when the state gets updated onChange and hence you can only enter only one character at a time. It is generally not a great idea to declare a component within a component. Refer this link for more info. All you have to do is pull the FormEdit component out of the App component in its own separate function and pass the change handlers as props to the FormEdit component. Have a look at the working code below.
import React, { useState } from 'react';
const FormEdit = ({ handleChange, submitEdit, name }) => {
return (
<form>
<div className='form-group'>
<input onChange={handleChange('name')} type='text' value={name || ''} />
</div>
<button onClick={submitEdit} type='submit'>
Submit
</button>
</form>
);
};
export default function App() {
const [userdata, setUser] = useState();
const { name } = userdata || {};
const handleChange = key => event => {
setUser(prevState => {
return { ...prevState, [key]: event.target.value };
});
event.persist();
event.preventDefault();
};
const submitEdit = event => {
event.preventDefault();
handleChange();
};
return (
<div>
<div>
{name || ''}
<FormEdit
handleChange={handleChange}
submitEdit={submitEdit}
name={name}
/>
</div>
</div>
);
}

Resources