React js a problem about updating the state value [duplicate] - json

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
Closed 2 years ago.
i'am just a newbie at React , i'am trying to make a form , when submitting i call a function "handleSubmit" that saves all the information into the state, and then displaying it into a grid , but it wont work for some reasons .
i really do need your help : here is my code :
export default class products extends React.Component {
constructor() {
super();
this.handleSubmit = this.handleSubmit.bind(this);
this.state =
{
QrCode: ''
}
}
handleSubmit(event) {
event.preventDefault();
const data = new FormData(event.target);
data.set('username', data.get('username').toUpperCase());
this.setState({QrCode: data});
console.log(this.state);
}
render() {
return (
<div >
<div >
<form onSubmit={this.handleSubmit}>
<label htmlFor="username">Enter username</label>
<input id="username" name="username" type="text" />
<button>Send data!</button>
</form>
</div>
<div style={{margin: '10%', marginTop : '5%'}}>
<GridComponent dataSource={this.state} />
</div>
</div>
);
}
}
and here what i get :
i keep getting empty array
and thank you.

In React, you don't need use form to take values from inputs.
export default class App extends React.Component {
constructor() {
super();
this.state = {
userName: ""
};
}
render() {
return (
<div className="App">
<label htmlFor="username">Enter username</label>
<input
value={this.state.userName}
onChange={e => this.setState({ userName: e.target.value })}
name="username"
type="text"
/>
<button
onClick={() => {
alert(this.state.userName);
}}
>
Send data!
</button>
</div>
);
}
}
Hope it help you!

Related

React - HTML form validation doesn't work

I work on a React project. I wrote HTML codes for create form. There is validation in HTML scripts. I wrote validations but validations doesn't work. The code is below. For example I want the relevant field to be red when the name is not entered or I want it to give a warning message when the name does not comply with the text rules. I must do it without any library. How can I fix it ?
import React, { Component } from 'react'
import EmployeeService from '../services/EmployeeService';
class CreateEmployeeComponent extends Component {
constructor(props) {
super(props)
this.state = {
id: this.props.match.params.id,
firstName: '',
lastName: '',
emailId: ''
}
}
componentDidMount(){
if(this.state.id === '_add'){
return
}else{
EmployeeService.getEmployeeById(this.state.id).then( (res) =>{
let employee = res.data;
this.setState({firstName: employee.firstName,
lastName: employee.lastName,
emailId : employee.emailId
});
});
}
}
saveOrUpdateEmployee = (e) => {
e.preventDefault();
let employee = {firstName: this.state.firstName, lastName: this.state.lastName, emailId: this.state.emailId};
console.log('employee => ' + JSON.stringify(employee));
// step 5
if(this.state.id === '_add'){
EmployeeService.createEmployee(employee).then(res =>{
this.props.history.push('/employees');
});
}else{
EmployeeService.updateEmployee(employee, this.state.id).then( res => {
this.props.history.push('/employees');
});
}
}
changeFirstNameHandler= (event) => {
this.setState({firstName: event.target.value});
}
changeLastNameHandler= (event) => {
this.setState({lastName: event.target.value});
}
changeEmailHandler= (event) => {
this.setState({emailId: event.target.value});
}
cancel(){
this.props.history.push('/employees');
}
getTitle(){
if(this.state.id === '_add'){
return <h3 className="text-center">Add Employee</h3>
}else{
return <h3 className="text-center">Update Employee</h3>
}
}
onSubmit = e => {
e.preventDefault();
}
render() {
return (
<div>
<br></br>
<div className = "container">
<div className = "row">
<div className = "card col-md-6 offset-md-3 offset-md-3">
{
this.getTitle()
}
<div className = "card-body">
<form onSubmit={this.onSubmit} noValidate>
<div className = "form-group">
<label for="validationCustom01" class="form-label">First name</label>
<input type='text' maxLength={20} pattern='[A-Za-z]' placeholder="First Name" name="firstName" className="form-control"
value={this.state.firstName} onChange={this.changeFirstNameHandler} required/>
</div>
<div className = "form-group">
<label> Last Name: </label>
<input type='text' maxLength={20} pattern='[A-Za-z]'class="form-control" placeholder="Last Name" name="lastName" className="form-control"
value={this.state.lastName} onChange={this.changeLastNameHandler} required/>
</div>
<div className = "form-group">
<label> Email Id: </label>
<input type='email' maxLength={35} pattern='[A-Za-z]' placeholder="Email Address" name="emailId" className="form-control"
value={this.state.emailId} onChange={this.changeEmailHandler} required/>
</div>
<button type="submit" className="btn btn-success" onClick={this.saveOrUpdateEmployee}>Save</button>
<button className="btn btn-danger" onClick={this.cancel.bind(this)} style={{marginLeft: "10px"}}>Cancel</button>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CreateEmployeeComponent
Remove noValidate from your <form> element.
Additionally, I've personally found that Formik and Yup can be a helpful library.
(Sorry I missed that "no libraries" wasa constraint)
Edit:
I was a muppet and forgot to change the pattern
You can do one of 2 things:
Remove maxLength and change the pattern to pattern="[A-Za-z]{1,20}"
Where 20 will be the new max-length (so 20 or 35, depending on the field)
Only change the pattern to be pattern="[A-Za-z]+"
The + is needed to ensure 1 or more of the [A-Za-z] regex is done. https://regexr.com/
Also don't forget to remove noValidate from your <form> element.
This answer may also prove helpful in setting custom validity status messages and callbacks.

Trying to add scroll event listener on window, but getting Uncaught TypeError: Cannot read property 'classList' of null

I am trying to add the bottom shadow to the search bar on scroll in react js. it is working well until I go on the second page of my app.
When I am trying to go on the second page, it showing
Uncaught TypeError: Cannot read property 'classList' of null
Not working code :
import React, { useEffect } from 'react';
import { AiOutlineSearch } from "react-icons/ai";
const SearchBar = ({ totalPrograms, programs, setPrograms }) => {
const handleScroll = () => {
if(window.scrollY) {
document.getElementById('sb-header').classList.add('h-shadow');
}
else {
document.getElementById('sb-header').classList.remove('h-shadow');
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {window.removeEventListener('scroll', handleScroll)};
},[]);
const handleSubmit = (event) => {
event.preventDefault();
const searchProgramName = document.getElementById('search').value;
if(searchProgramName) {
setPrograms(
programs.filter(program =>
program.name.toLowerCase().includes(searchProgramName)
)
);
}
else {
handleClick();
}
}
const handleClick = () => {
const allPhase = document.getElementsByName('phase');
const checkedPhaseValue = [];
allPhase.forEach(phase => {
if(phase.checked) {
checkedPhaseValue.push(phase.value);
}
});
setPrograms(checkedPhaseValue.length ?
totalPrograms.filter(
program => checkedPhaseValue.includes(program.phase.toLowerCase())
)
: totalPrograms
);
}
return (
<header id='sb-header' className="container header-sb">
<form className="container container-center" onSubmit={handleSubmit}>
<div className="type-search">
<AiOutlineSearch className="icon"/>
<input id="search" type="search" placeholder="search by program name"/>
</div>
<div className="checkbox-container">
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="open_application" value="application_open"/>
<label htmlFor="open_application">Open Application</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="application_in_review" value="application_review"/>
<label htmlFor="application_in_review">Application in Review</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="in_progress" value="in_progress"/>
<label htmlFor="in_progress">in Progress</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="completed" value="completed"/>
<label htmlFor="completed">Completed</label>
</div>
</div>
</form>
</header>
)
}
export default SearchBar;
On the second page, I am going by clicking on the Details button. Code for that :
import React from 'react';
import { Link } from 'react-router-dom';
import { FaAngleDoubleRight } from 'react-icons/fa';
import * as ROUTES from '../Constants/routes';
const ProgramCards = ({ program }) => {
return (
<div className="card">
<div className="card-header">
<h1 className="p-name">{program.name}</h1>
</div>
<div className="card-body">
<h3 className="p-category">{program.category}</h3>
<small className="p-phase">{(program.phase).replace('_', ' ')}</small>
<p className="p-description">{program.shortDescription}</p>
</div>
<div>
<div className="date-duration">
<small className="p-date">Start Date: {program.startDate}</small>
<small className="p-duration">Duration: {program.duration}</small>
</div>
<Link to={ROUTES.PROGRAM_DETAILS}>
<button className="card-button">
Details <FaAngleDoubleRight className="icon angled-icon" />
</button>
</Link>
</div>
</div>
)
}
export default ProgramCards;
My question is, why it is not working?
After this, I tried a different approach. And it is working well.
Working code :
import React, { useEffect, useState } from 'react';
import { AiOutlineSearch } from "react-icons/ai";
const SearchBar = ({ totalPrograms, programs, setPrograms }) => {
const [ scrolled, setScrolled ] = useState(false);
const handleScroll = () => {
if(window.scrollY > 10) {
setScrolled(true);
}
else {
setScrolled(false);
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {window.removeEventListener('scroll', handleScroll)};
},[]);
const handleSubmit = (event) => {
event.preventDefault();
const searchProgramName = document.getElementById('search').value;
if(searchProgramName) {
setPrograms(
programs.filter(program =>
program.name.toLowerCase().includes(searchProgramName)
)
);
}
else {
handleClick();
}
}
const handleClick = () => {
const allPhase = document.getElementsByName('phase');
const checkedPhaseValue = [];
allPhase.forEach(phase => {
if(phase.checked) {
checkedPhaseValue.push(phase.value);
}
});
setPrograms(checkedPhaseValue.length ?
totalPrograms.filter(
program => checkedPhaseValue.includes(program.phase.toLowerCase())
)
: totalPrograms
);
}
return (
<header className={`container header-sb ${scrolled && 'h-shadow'}`}>
<form className="container container-center" onSubmit={handleSubmit}>
<div className="type-search">
<AiOutlineSearch className="icon"/>
<input id="search" type="search" placeholder="search by program name"/>
</div>
<div className="checkbox-container">
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="open_application" value="application_open"/>
<label htmlFor="open_application">Open Application</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="application_in_review" value="application_review"/>
<label htmlFor="application_in_review">Application in Review</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="in_progress" value="in_progress"/>
<label htmlFor="in_progress">in Progress</label>
</div>
<div className="d-inline">
<input type="checkbox" onClick={handleClick} name="phase" id="completed" value="completed"/>
<label htmlFor="completed">Completed</label>
</div>
</div>
</form>
</header>
)
}
export default SearchBar;
Your second approach is the better and the react way to do it. It is generally discouraged to query the DOM managed by react yourself. Use ref's if you need the DOM node.
The first example is not working because handleScroll will be recreated every time the component re-renders. Therefore removing the listener will not remove the original listener as the function referenced by handleScroll has changed.
Therefore when your component unmounts the listener will not be removed correctly but react will remove the DOM node. Next time you scroll the handler will still be called but the node you are trying to query isn't there anymore.
You have to create the listener inside of useEffect so that your removeEventListener references the correct function:
useEffect(() => {
const handleScroll = () => setScrolled(window.scrollY > 10);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
},[]);
Alternatively you could use useRef to create a stable reference to you listener function.

show login page for a second when routering other pages reactJS

I use this video https://www.youtube.com/watch?v=r4EsP6rovwk&t=1s to create an Auth for my website,
i basically copied his code the only change is that I route after successful login to different page.
the problem is that after login my home page is shown, but when I'm pressing buttons to route for other pages, before the other page is shown I see for a second the login page.
this is the code of the auth - I believe it connect to the problem (before this my website has worked well).
Edit:
i try to figure out what's the problem and I've noticed that when i'm using link everything's fine, but when using href there's a problem.
(And that's what I did in my website).
So... does anyone know why href makes this issue?
app.js
import React, { Component } from 'react';
import fire from './Fire';
import SearchAppBar from '../components/appBar';
import Login from './login';
class App extends Component {
constructor() {
super();
this.state = ({
user: null,
});
this.authListener = this.authListener.bind(this);
}
componentDidMount() {
this.authListener();
}
authListener() {
fire.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ user });
} else {
this.setState({ user: null });
}
});
}
render() {
return (
<div>{this.state.user ? ( <SearchAppBar/>) : (<Login />)}</div>)
}
}
export default App;
login.js:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import fire from './Fire';
class Login extends Component {
constructor(props) {
super(props);
this.login = this.login.bind(this);
this.handleChange = this.handleChange.bind(this);
this.signup = this.signup.bind(this);
this.state = {
email: '',
password: ''
};
}
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
login(e) {
e.preventDefault();
fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password).then((u)=>{
}).catch((error) => {
console.log(error);
});
}
signup(e){
e.preventDefault();
fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then((u)=>{
}).then((u)=>{console.log(u)})
.catch((error) => {
console.log(error);
})
}
render() {
return (
<div className="col-md-6">
<form>
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input value={this.state.email} onChange={this.handleChange} type="email" name="email"
class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter
email" />
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.
</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input value={this.state.password} onChange={this.handleChange} type="password" name="password"
class="form-control" id="exampleInputPassword1" placeholder="Password" />
</div>
<button type="submit" onClick={this.login} className="btn btn-primary">Login</button>
<button onClick={this.signup} style={{marginLeft: '25px'}} className="btn btn-
success">Signup</button>
</form>
</div>
);
}
}
export default Login;
Thank you all guys!!

Convert HTML form with action to React form submit with logic

Folks, I think I'm either missing something here or I don't know what I don't know.
What I have is:
<form action="/orders/populate" method="post">
<input type="hidden" name="name" id="name"/>
<input type="hidden" name="rating" id="rating"/>
<input type="submit" name="commit" value="Rate Now" />
</form>
What I want to do is:
Class myComponent extends React.PureComponent {
handleSubmit(e) {
e.preventDefault(); // don't know if this is necessary
sendAnalytics();
// then form submit
}
render () {
return (
<form action="/orders/populate" method="post" onSubmit={this.handleSubmit.bind(this)}>
<input type="hidden" name="name" id="name"/>
<input type="hidden" name="rating" id="rating"/>
<input type="submit" name="commit" value="Rate Now" />
</form>
);
}
}
Don't know what has to be done here. Can someone point out an example similar to this? Or perhaps give me a sample code below?
All help appreciated.
Class myComponent extends React.PureComponent {
this.state = {
name: '' // initial value for name
rating: '' // initial value for rating
}
handleInput = e => {
this.setState({[e.target.name]: e.target.value})
}
handleSubmit = e => {
const { name, rating } = this.state;
e.preventDefault(); // yes, this is necessary otherwise it's refresh your page.
sendAnalytics(name, rating); // api call to store in DB. to call API use axios npm package
}
render () {
const { name, rating } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<input type="text" name="name" value={name} id="name" onChange={(e) => this.handleSubmit(e)}/>
<input type="text" name="rating" value={rating} id="rating" onChange={(e) => this.handleSubmit(e)}/>
<input type="submit" name="commit" value="Rate Now" />
</form>
);
}
}
Have you looked at the docs for handling forms in React? This will give you insights in how to use forms with react, since it handles a bit different than regular html forms
This is a common problem I've faced in React. You have one of three ways:
1) Use a third party React-Form library to do the job. There are several.
2) Use React-hooks (a very recent addition to React).
3) Create a generic Form class to handle this state management for you...like so:
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
values: {}
};
}
#boundMethod
handleSubmit(event) {
event.preventDefault();
this.props.submit(this.state.values);
}
#boundMethod
handleChange(event) {
const { name, value } = event.target;
const newValues = Object.assign(
{ ...this.state.values },
{ [name]: value }
);
this.setState({
values: newValues
});
}
public render() {
const { values } = this.state;
return (
<form onSubmit={this.handleSubmit} noValidate={true}>
<div>
{React.Children.map(
this.props.children,
child => (
{React.cloneElement(child, {
value: values[child.props.name],
onChange: this.handleChange
})}
)
)}
<div>
<button type="submit">
Submit
</button>
</div>
</div>
</form>
);
}
}
Then you will be able to use this Form class like so:
<Form
submit={values => {
/* work with values */
}}
>
<input type="hidden" name="name" />
<input type="hidden" name="rating" />
</Form>;
PS:
Keep in mind boundMethod Decorator is something that is not natively available but a module called 'autobind-decorator' I tend to use a lot to deal with this not being bound.

Passing a html value as a parameter in react

I need to pass a html value as a parameter for my function like so:
<input type ="text" placeholder="Smart Contract Bytecode" name="name" id ="scbytecode"className="nice-textbox"/>
<button id="button" onClick={parseAddress("document.getElementById('smartcontract').value)"}>Submit!</button>
but Im getting an error:
TypeError: Cannot read property 'value' of null
here is the Full code.
Added this to give a better impression of whats going on cause the fixes below don't seem to fix it all. Any help is welcomed.
class App extends Component {
parseAddress(_smartcontract){
var contractObj = new ethweb3.eth.Contract(ERC20ABI, document.getElementById('smartcontract').value);
contractObj.getPastEvents(
'Transfer' || 'allEvents',
{
fromBlock: 0,
toBlock: 'latest'
},
function(err,res){
console.log(err,res);
//examples to access the data returned
console.log(res.length);
document.getElementById("totalAddresses").innerHTML = res.length;
document.getElementById("sampleAddress").innerHTML = res[0].returnValues.from;
document.getElementById("sampleAmount").innerHTML = res[0].returnValues.value;
}
);
}
deploSC = async () => {
const accounts = await goweb3.eth.getAccounts();
//const code = ethweb3.eth.getCode(document.getElementById('smartcontract').value); Not working
console.log(code);
goweb3.eth.sendTransaction({
from: accounts[0],
data: document.getElementById('scbytecode').value
}, function(error, hash){
console.log(error,hash);
});
}
render() {
return (
<div className="App">
<header className="App-header">
<p>
Enter the smart contract address:
<input type="text" name="name" id="smartcontract" className="nice-textbox"/>
<input type ="text" placeholder="Sc bytecode" name="name" id ="scbytecode"className="nice-textbox"/>
<button id="button" onClick={this.parseAddress}>Submit!</button>
<button onClick={this.deploSC}> Deploy Sc</button>
</p>
<p id="totalAddresses">0</p>
<p id="sampleAddress">0</p>
<p id="sampleAmount">0</p>
</header>
</div>
);
}
}
export default App;
There is a better way to do this in React using state and not directly accessing the DOM which should be avoided.
Store the value of an input in the component's state, then give it to the button's onClick event handler via this.state.inputVal.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
inputVal: ''
};
}
inputChanged = (e) => {
this.setState({ inputVal: e.target.value });
}
render() {
return (
<div>
<input type ="text" placeholder="Smart Contract Bytecode" name="name" id ="scbytecode" className="nice-textbox" onChange={this.inputChanged}/>
<button id="button" onClick={() => { console.log(this.state.inputVal); }}>Submit!</button>
</div>
);
}
}
// Render it
ReactDOM.render(
<App/>,
document.getElementById("react")
);
<div id="react"></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>
I think there is mismatch in id.
line 1 you gave "scbytecode"
line 2 you are trying access by id "smartcontract" which is not present, so you are seeing null