Why react default form feature is not executing? - javascript

import React from "react";
export default class Form extends React.Component{
constructor(props) {
super(props);
this.inputRef = React.createRef();
this.state = {
value:""
}
}
// handleClick
handleClick = (e) => {
this.setState({ value: e.target.value })
console.log(e.target.value)
}
render() {
return <>
<h2>Typig ... {this.state.value} </h2>
<form>
<input type="text" ref={this.inputRef} onChange={this.handleClick} />
</form>
</>
}
}
I learnt that we can't change the value of any input tag in react, we have to do it manually by writing handler function but in the above code snippet i haven't change value explicitly then why here the default behaviour is not applied
In the above code snippet i have not change the value of the input tag explicitely then why react default feature is not applied here

Transform your Input like this:
<input type="text" value={this.state.value} ref={this.inputRef} onChange={e => this.handleClick} />

Related

Confusion around 'value' parameter for <input> tag in REACTjs

I'm a bit confused regarding the 'value' parameter and it's assignment.
From here Can't type in React input text field
I understood that when setting a value parameter, that disables the possibility of entering a value to the input box
YET, if we notice the following code (with a focus on the render method - I will put the whole code in the bottom of this question):
import React, { Component } from 'react'
export default class NewBoxForm extends Component {
constructor(props){
super(props);
this.state = {
height: "",
width: "",
backgroundColor: ""
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(evt){ //handles any form of change in the input.
evt.preventDefault(); // prevents refresh of page
this.setState({
[evt.target.name]: evt.target.value
});
}
handleSubmit(evt){
evt.preventDefault();
console.log(this.state)
this.props.handleSubmit(this.state);
//need to use my parent's function to transfer information to parent.
//for that i will send my state, and he will update his state.
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label htmlFor='height'>Height: </label>
<input
name='height'
id='height'
type="number"
value={this.state.height}
onChange={this.handleChange}
/>
<label htmlFor='width'>Width: </label>
<input
name='width'
id='width'
type="number"
value={this.state.width}
onChange={this.handleChange}
/>
<label htmlFor='backgroundcolor'>BackgroundColor: </label>
<input
name='backgroundcolor'
id='backgroundcolor'
type="text"
value={this.state.backgroundColor}
onChange={this.handleChange}
/>
<button>Submit</button>
</form>
)
}
}
which works!
i'm able this way to insert a value to the input tag..
so, my question is, what is the rule of thumb? what is correct the correct way?
good habit vs bad hobbit (:D)
rest of the code:
import React, { Component } from 'react';
import Box from './Box';
import NewBoxForm from './NewBoxForm';
class BoxList extends Component {
constructor(props){
super(props);
this.state = {
boxes: [
{ width: 10, height: 20, backgroundColor: "red" },
{ width: 20, height: "200px", backgroundColor: "purple" },
{ width: "100px", height: "140px", backgroundColor: "yellow" },
]
};
this.handleSubmit = this.handleSubmit.bind(this);
}
// what i will get from my child(Box) ? A BOX, duh.
handleSubmit(newBox){
this.setState(st => ({
boxes: [...st.boxes, newBox]
}))
console.log(this.state);
}
render() {
let boxes2show = this.state.boxes.map(box => (
<Box
width={box.width}
height={box.height}
backgroundColor={box.backgroundColor}/>
))
return (
<div>
<h1>BoxList</h1>
<NewBoxForm handleSubmit={this.handleSubmit}/>
{boxes2show}
</div>
)
}
}
export default BoxList;
import React, { Component } from 'react'
export default class Box extends Component {
constructor(props){
super(props);
}
render() {
const myStyle = {
backgroundColor: this.props.backgroundColor,
width: `${this.props.width}em`,
height: `${this.props.height}em`
};
return (
<div style={myStyle}>
I'm a box.
sa
</div>
)
}
}
cheers
I think you misunderstood the answer. In React, inputs came in two variants (see Docs):
controlled
uncontrolled
Controlled inputs are given a value={valueState} to it, which prevents any changes from the user if valueState isn't updated inside the component. The following example is a controlled input, that can't be changed, because it has no change event handler:
export default function App() {
const value = 'test';
return (
<div className="App">
<input value={value} />
</div>
);
}
To allow user input, you need to react to changes:
export default function App() {
const [value, setValue] = useState('test')
return (
<div className="App">
<input value={value} onChange={(e) => setValue(e.currentTarget.value)} />
</div>
);
}
On the other hand there are uncontrolled inputs. Those don't receive a value input. But they can receive a defaultValue (React speciality) to allow initialy setting a value to it a user can change:
export default function App() {
const value = "test";
const ref = useRef();
const submit = (e) => {
e.preventDefault();
// get data
console.log(ref.current.value);
};
return (
<form className="App" onSubmit={submit}>
<input defaultValue={value} ref={ref} />
<button>Submit</button>
</form>
);
}

React - How can I make a component from a function inside a parent component?

New to React - I have a component AddForm that looks like this:
class AddForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
};
}
handleInput = event => {
this.setState({ name: event.target.value });
};
logValue = () => {
console.log(this.state.name)
return <Display text={this.state.name} />
};
render() {
return (
<div>
<input onChange={this.handleInput}
placeholder="Type Here" type="text" />
<button onClick={this.logValue}
type="submit">Submit</button>
</div>
)
}
}
And when the user clicks on the "Submit" button I want it to display what was in the form. I stored the value in form in this.state.name and my component for displaying the text inside of the form looks like this:
class Display extends React.Component {
render() {
return (
<h1>{this.props.text}</h1>
)
}
}
I know that I the state.name can access the form because I console.logged it. I just want to know why my return statement in the logValue function in the AddForm component isn't creating a new component, Display, and how can I make it work?
The click of the button should result in a state change that the render method then uses to return the Display component - something like:
logValue = () => {
this.setState({ showingName: !this.state.showingName });
}
render() {
return (
<div>
{
this.state.showingName ? <Display text={this.state.name} /> : null
}
<input onChange={this.handleInput}
placeholder="Type Here" type="text" />
<button onClick={this.logValue}
type="submit">Submit</button>
</div>
)
}

Passing handleSubmit() to child component does not modify parent's state

I am new to React and Javascript.
I am trying to have a user fill in a form that describes what a "Mob" should look like. When the user hits submit, I expect handleSubmit() (passed in through a parent) to modify the parent's state, which is an object. However, this behavior is not happening.
Here is the parent component, called App.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
mob: new Mob("", "")
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
alert("A name was submitted: " + this.state.vnum + " event value: " + event.state.vnum);
const newMob = new Mob(event.state.vnum, event.state.shortDesc);
this.setState({
mob: newMob
});
}
render() {
return (
<div>
<MobForm mob={this.state.mob} onSubmit={() => this.handleSubmit} />
{console.log("parsed mob vnum: " + this.state.mob.vnum)}
</div>
);
}
}
The child component, called MobForm
class MobForm extends React.Component {
render() {
return (
<div>
<form onSubmit={this.props.onSubmit}>
<CreateStringInputField
name="vnum"
label="vnum:"
/>
<CreateStringInputField
name="shortDesc"
label="Short Desc:"
/>
<input type="submit" value="Submit" />
</form>
{console.log(this.state)}
</div>
);
}
}
Which is calling CreateStringInputField()
function CreateStringInputField(props) {
return (
<div name="row">
<label>
<b>{props.label}</b>
<br />
<input
type="text"
name={props.name}
label={props.label}
/>
</label>
</div>
);
}
And, in case it matters, here is what "Mob" looks like.
class Mob {
constructor(vnum, shortDesc) {
this.vnum = vnum;
this.shortDesc = shortDesc;
};
}
I expect to see {console.log("parsed mob vnum: " + this.state.mob.vnum)} print out the vnum as entered by a user. Instead, I see nothing. How can I achieve this expected output?
With React you won't need to work with plain classes. Instead, the class extends a provided React component (Component or PureComponent) or if you don't need state, then'll use plain functions that just return some JSX.
Working example: https://codesandbox.io/s/simple-form-kdh3w
index.js
import React from "react";
import { render } from "react-dom";
import MobForm from "./components/MobForm";
// simple function that returns "MobForm" and it gets rendered by ReactDOM
function App() {
return <MobForm />;
}
// applies "App" to a <div id="root"></div> in the public/index.html file
render(<App />, document.getElementById("root"));
components/MobForm/index.js (stateful parent component)
import React, { Component } from "react";
import Form from "../Form";
const initialState = {
vnum: "",
shortDesc: ""
};
// a stateful parent that manages child state
class MobForm extends Component {
constructor(props) {
super(props);
this.state = initialState;
// since the class fields are normal functions, they'll lose context
// of "this" when called as a callback. therefore, they'll need
// to be bound to "this" -- via bind, "this" is now referring to
// the Class, instead of the global window's "this")
this.handleChange = this.handleChange.bind(this);
this.handleReset = this.handleReset.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
// a reusable class field that stores an input's value via its "name"
// for example: [vnum]: "12345", [shortDesc]: "A number"
// using object destructuring for shorter syntax:
// [event.target.name]: event.target.value
handleChange({ target: { name, value } }) {
this.setState({ [name]: value });
}
// a class field to reset state
handleReset() {
this.setState(initialState);
}
// a class field to "submit" the form and alert what's currently in state
handleSubmit(event) {
// preventDefault prevents page refreshes
event.preventDefault();
// JSON.stringify allows you to print the contents of an object
// otherwise, you'll just see [object Object]
alert(JSON.stringify(this.state, null, 4));
// clears state after submitting form
this.handleReset();
}
render() {
return (
// passing down state via the spread operator, shorthand for
// "vnum={this.state.vum}" and "shortDesc={this.state.shortDesc}",
// as well as, passing down the class fields from above
<Form
{...this.state}
handleChange={this.handleChange}
handleReset={this.handleReset}
handleSubmit={this.handleSubmit}
/>
);
}
}
export default MobForm;
components/Form/index.js (a child function that returns some form JSX)
import React from "react";
import PropTypes from "prop-types";
import Input from "../Input";
// using object destructuring to pull out the MobForm's passed down
// state and fields. shorthand for using one parameter named "props"
// and using dot notation: "props.handleChange", "props.handleReset", etc
function Form({ handleChange, handleReset, handleSubmit, shortDesc, vnum }) {
return (
<form style={{ width: 200, margin: "0 auto" }} onSubmit={handleSubmit}>
<Input name="vnum" label="vnum:" value={vnum} onChange={handleChange} />
<Input
name="shortDesc"
label="Short Desc:"
value={shortDesc}
onChange={handleChange}
/>
<button type="button" onClick={handleReset}>
Reset
</button>{" "}
<button type="submit">Submit</button>
</form>
);
}
// utilizing "PropTypes" to ensure that passed down props match
// the definitions below
Form.propTypes = {
handleChange: PropTypes.func.isRequired,
handleReset: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
shortDesc: PropTypes.string,
vnum: PropTypes.string
};
export default Form;
components/Input/index.js (a reuseable input function)
import React from "react";
import PropTypes from "prop-types";
// once again, using object destructuring to pull out the Form's
// passed down state and class fields.
function Input({ label, name, value, onChange }) {
return (
<div name="row">
<label>
<b>{label}</b>
<br />
<input
type="text"
name={name}
label={label}
value={value}
onChange={onChange}
/>
</label>
</div>
);
}
// utilizing "PropTypes" to ensure that passed down props match
// the definitions below
Input.propTypes = {
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.string,
onChange: PropTypes.func.isRequired
};
export default Input;
In this line
<MobForm mob={this.state.mob} onSubmit={() => this.handleSubmit} />
you are defining an anonymous function that returns your handleSubmit function.
In your form
<form onSubmit={this.props.onSubmit}>
onSubmit will execute the this.props.onSubmit which just returns the handleSubmit function but it wont execute it. To fix it just change MobForm to pass handleSubmit directly instead of passing it in an anonymous function:
<MobForm mob={this.state.mob} onSubmit={this.handleSubmit} />
To handle the submission correctly you need to convert your form inputs to managed components. See docs here
Something like this would be a good start:
class MobForm extends React.Component {
constructor(props) {
super(props);
this.state = {
vnum: '',
shortDesc: '',
};
this.handleChangeVnum = this.handleChangeVnum.bind(this);
this.handleChangeShortDesc = this.handleChangeShortDesc.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeVnum(event) {
this.setState({vnum: event.target.value});
}
handleChangeShortDesc(event) {
this.setState({shortDesc: event.target.value});
}
handleSubmit(event) {
this.props.onSubmit(this.state);
event.preventDefault();
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<CreateStringInputField
name="vnum"
label="vnum:"
value={this.state.vnum}
onChange={this.handleChangeVnum}
/>
<CreateStringInputField
name="shortDesc"
label="Short Desc:"
value={this.state.shortDesc}
onChange={this.handleChangeShortDesc}
/>
<input type="submit" value="Submit" />
</form>
{console.log(this.state)}
</div>
);
}
}
And update CreateStringInputField()
function CreateStringInputField(props) {
return (
<div name="row">
<label>
<b>{props.label}</b>
<br />
<input
type="text"
name={props.name}
label={props.label}
value={props.value}
onChange={props.onChange}
/>
</label>
</div>
);
}
I was able to get my desired behavior by passing a function to MobForm which updates this.state.mob.
App
class App extends React.Component {
state = {
mob: new Mob("", "")
};
updateMob = newMob => {
this.setState({
mob: newMob
});
};
render() {
return (
<div>
<MobForm mob={this.state.mob} onSubmit={this.updateMob} />
</div>
);
}
}
I then made MobForm maintain vnum, shortDesc state that I could use in my onChange()
MobForm
state = { vnum: "", shortDesc: "" };
handleSubmit = event => {
event.preventDefault();
const mob = new Mob(this.state.vnum, this.state.shortDesc);
this.props.onSubmit(mob);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<CreateStringInputField
name="vnum"
value={this.state.vnum}
onChange={event => this.setState({ vnum: event.target.value })}
/>
<CreateStringInputField
name="short desc"
value={this.state.shortDesc}
onChange={event => this.setState({ shortDesc: event.target.value })}
/>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}

How can the value go from the Child element to the sister Element in React | JSX

I am taking a date from the drop down date picker and trying to use it in another page so I can cross reference times open for bookings. When the Datepicker selects a date, and The props value is set on the Btnsearch It tries to redirect and seems like it does rerender but the prop value is undefined while the wasSubmit changes to true. Where do I pull this prop from?
I have added what I thought was a router, I set the sate with an attribute this.state.value but that does not seem to fix the issue.
Here is my Date Picker, Btnsearch, Bookingpage
import "./Btnsearch/Btnsearch";
// react plugin used to create datetimepicker
import ReactDatetime from "react-datetime";
import { Redirect } from 'react-router-dom';
import Bookingpage from "./Bookingpage/Bookingpage";
// reactstrap components
import {
FormGroup,
InputGroupAddon,
InputGroupText,
InputGroup,
Col,
Row
} from "reactstrap";
import Btnsearch from "./Btnsearch/Btnsearch";
class Datepicker extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
//this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = event => {
event.preventDefault();
this.setState({wasSubmitted: true});
}
render() {
const { value, wasSubmitted } = this.state;
if (wasSubmitted) {
return <Bookingpage><Redirect value={this.state.value} to='./Bookingpage/Bookingpage' /></Bookingpage>
} else {
return (
<>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText
>
<i className="ni ni-calendar-grid-58" />
</InputGroupText>
</InputGroupAddon>
<ReactDatetime
value={this.state.value}
onChange={this.handleChange}
inputProps={{
placeholder: "Date Picker Here"
}}
timeFormat={false}
/>
</InputGroup>
</FormGroup>
<form onSubmit={this.handleSubmit}>
<Btnsearch type="submit" value={this.state.value}/>
</form>
</>
);
}
}
}
export default Datepicker;
import '../Datepicker';
class Btnsearch extends React.Component {
render() {
return (
<button onClick={() => console.log(this.props.value)} className="btn btn-success search-card-btn">Search</button>
);
}
};
export default Btnsearch;
import '../Datepicker';
class Bookingpage extends React.Component {
render() {
return(
<div className="bookingPage">
<h1>{this.props.value}</h1>
</div>
);
}
}
export default Bookingpage;
When Select the date and hit the search btn I expect it to redirect to a page Bookingpage that says the value selected. The Actual results are
<div class="App">
<div class="card freesearch-option">
<label><span class="searchTitleTxt">Search For Availability</span>
<div class="bookingPage">
<h1></h1></div>
</label>
</div>
</div>
State
value:
""
wasSubmitted: true
The full project is here https://react-puh2oq.stackblitz.io
I don't see a handleChange function.
So it seems like you are picking a date but not .setState()ing the this.state.value.
<ReactDatetime
value={this.state.value}
// HERE YOU CALL IT, BUT handleChange DOESN'T EXIST.
onChange={this.handleChange}
inputProps={{
placeholder: "Date Picker Here"
}}
timeFormat={false}
/>
Well, a proper handleChange function could be like this:
.
.
.
handleSubmit = event => {
event.preventDefault();
this.setState({wasSubmitted: true});
}
handleChange = e => {
e.preventDefault();
this.setState({ value: e.target.value });
}
render() {
const { value, wasSubmitted } = this.state;
if (wasSubmitted) {
return <Bookingpage><Redirect value={this.state.value} to='./Bookingpage/Bookingpage' /></Bookingpage>
} else {
.
.
.
You don't have to .bind() neither this function nor handleSubmit as long as you use fat arrow syntax.

controlled components in form

I have this form where I want the name and gender of the user and I change state accordingly but my code seems to fail as the output don't match what i want.
Here is the code.
class Addoption extends React.Component{
constructor(props){
super(props);
this.state={
name:'',
gender:''
};
this.handleaddoption=this.handleaddoption.bind(this);
}
handleaddoption(event){
event.preventDefault();
const nameofuser=event.target.elements.nametext.value;
const genderofuser=event.target.elements.gendertext.value;
this.setState({
name:nameofuser,
gender:genderofuser
});
console.log(this.state.name);
console.log(this.state.gender);
}
render(){
return(
<div>
<form >
<input type="text" name="nametext" placeholder="name" onChange={this.handleaddoption}/>
<input type="text" name="gendertext" placeholder="gender" onChange={this.handleaddoption}/>
</form>
</div>
);
}
}
export default App;
When the user enters the name and the age ,I don't see his age and name in console instead error which says cannot read Cannot read property 'nametext' of undefined.
I tried one more method even that doesn't seem to work.
handleaddoption(event){
event.preventDefault();
const nameofuser=event.target.elements.nametext.value;
const genderofuser=event.target.elements.gendertext.value;
this.setState({
name:nameofuser,
gender:genderofuser
});
console.log(this.state.name);
console.log(this.state.gender);
}
render(){
return(
<div>
<form onSubmit={this.handleaddoption}>
<input type="text" name="nametext" placeholder="name" />
<input type="text" name="gendertext" placeholder="gender"/>
</form>
</div>
);
}
}
You need to handle the event a little different.
Your handler function receives an event object, and the event.target is actually the input.
Change your input names so you can directly reference the state with them.
Then check out the component lifecycle, you can't see the updates because of how the component rendering works in react. Notice I used the componentDidUpdate method which runs after the setState is completed and there the logs show the new state.
Here's the link to the lifecycle docs: https://reactjs.org/docs/state-and-lifecycle.html
import React from 'react'
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { name: '', gender: '' }
this.handleChange = this.handleChange.bind(this)
}
componentDidUpdate() {
console.log('gender 1', this.state.gender)
console.log('name 1', this.state.name)
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
console.log('gender', this.state.gender)
console.log('name', this.state.name)
}
render() {
return (
<form action="">
<input type="text" name="gender" value={this.state.gender || ''} onChange={this.handleChange}/>
<input type="text" name="name" value={this.state.name || ''} onChange={this.handleChange}/>
</form>
)
}
}
export default MyComponent

Categories

Resources