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

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>
);
}
}

Related

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>
)
}

Why is my react form not working on codesandbox

I created a simple form here https://codesandbox.io/s/xenodochial-frog-7squw
It says You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue.
But there is an onChange handler being passed, so I don't understand. In addition the page reloads when I hit submit, even though preventDefault() is called
Thank you
The issue is this line:
const { str, handleChange, handleSubmit } = this.state;
handleChange and handleSubmit are not part of the state, but are instance methods, so you can pass them like so:
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
On line 25 you do:
const { str, handleChange, handleSubmit } = this.state;
Because of this, handleChange will be bound to this.state.handleChange which will be undefined as you have no property handleChange in your state.
You also forgot to pass the prop name to your Table-component.
I forked your code and updated it here: https://codesandbox.io/s/modest-meninsky-y1sgh
here is the correct Code for you:
import React from "react";
import "./styles/styles.css";
import Form from "./components/Form";
import Table from "./components/Table";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { str: "", desc: false };
console.log(4444);
this.handleChange = this.handleChange.bind(this); //<-- this binding
}
handleSubmit = event => {
event.preventDefault();
console.log("submitted");
};
handleChange = event => {
this.setState({ str: event.target.value });
};
render() {
const { str } = this.state; // <-- FIXED THIS
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
}
}
export default App;

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.

React : how to get input value from one component to make the ajax call in another component?

I am building a movie search React app using themoviedb.org API. in order to an make ajax call to pull the list of movies I need to get input value as a variable and feed to the url, but not sure how to fetch a value that belongs to another component.
I've made an extensive online search, but they mainly refer to the case when it happens inside the same component, and using ref is discouraged.
So what would be the best way (or at least most common or the simplest way) to fetch the input value variable from one component to pass down to another and attach to the end of url, while:
1) Keeping global space clean
2) Organizing the entire app in 'React way'
3) Keeping components decoupled
?
Would React Router necessary in this case?
import React from 'react';
import './App.css';
import axios from 'axios';
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
console.log("state value is " + this.state.value);
var searchValue = this.movieName.value;
console.log("ref value is "+ searchValue)
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input className="movieName" type="text" ref={(input) => { this.movieName = input; }} value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
<h1>{this.state.value}</h1>
</form>
);
}
}
class App extends NameForm{ /* I am extending NameForm to get access to input value, but probably coupling components too tight */
constructor(props) {
super(props);
this.state ={
movie:[]
};
}
componentDidMount() {
let searchInput = "land"; /* This should be from SearchForm's input value */
let sortByPop = "&sort_by=popularity.desc";
let requestUrl = 'https://api.themoviedb.org/3/search/movie?api_key=f8c4016803faf5e7f424abe98a04b8d9&query=' + searchInput + sortByPop;
axios.get(requestUrl).then(response => {
this.setState({movie: response.data.results})
});
}
render() {
let baseImgURL = "https://image.tmdb.org/t/p/w185_and_h278_bestv2";
let posterImgPath = this.state.movie.map(movie => movie.poster_path);
let posterLink = baseImgURL + posterImgPath;
return(
<div className="App">
<Header />
<SearchForm />
<div>
{this.state.movie.map(movie =>
<div className="movieTitle">
<div className="movieCard">
<img className="posterImg" src= {`https://image.tmdb.org/t/p/w185_and_h278_bestv2/${movie.poster_path}`} alt={movie.title} />
<div className="searchFilmTitles" key={movie.id}>{movie.title}</div>
</div>
</div>
)}
</div>
</div>
)
}
}
export default App;
componentDidMount get called only once when your component get attached to the page. So it's not the correct place to call you search API. Instead, you should call it every time when the user clicks 'submit' button. For that, you need to bubble handleSubmit trigger to App component by passing a callback method as a prop to SearchForm component. Also, you don't need to use ref as you already have search text in your state.
SearchForm
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
if(this.props.onSubmit && typeof this.props.onSubmit === "function"){
this.props.onSubmit(this.state.value);
}
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input className="movieName" type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
<h1>{this.state.value}</h1>
</form>
);
}
}
App
class App extends React.Component { /* I'm not sure why you extends NameForm and what NameForm does */
constructor(props) {
super(props);
this.state = {
movie:[]
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(value) {
let searchInput = value // you get the value of movieName input here
let sortByPop = "&sort_by=popularity.desc";
let requestUrl = 'https://api.themoviedb.org/3/search/movie?api_key=f8c4016803faf5e7f424abe98a04b8d9&query=' + searchInput + sortByPop;
axios.get(requestUrl).then(response => {
this.setState({movie: response.data.results})
});
}
render() {
let baseImgURL = "https://image.tmdb.org/t/p/w185_and_h278_bestv2";
let posterImgPath = this.state.movie.map(movie => movie.poster_path);
let posterLink = baseImgURL + posterImgPath;
// I'm not sure why use need above code as you don't use it anywhere
return(
<div className="App">
<Header />
<SearchForm onSubmit={this.handleSubmit}/>
<div>
{this.state.movie.map(movie =>
<div className="movieTitle">
<div className="movieCard">
<img className="posterImg" src= {`https://image.tmdb.org/t/p/w185_and_h278_bestv2/${movie.poster_path}`} alt={movie.title} />
<div className="searchFilmTitles" key={movie.id}>{movie.title}</div>
</div>
</div>
)}
</div>
</div>
);
}
}

React - Can A Child Component Send Value Back To Parent Form

The InputField & Button are custom components that go into a form to create a form. My issue is how do I send the data back up to form so that on button click, I can fire ajax on the form with data (username & password):
export default auth.authApi(
class SignUpViaEmail extends Component{
constructor(props){
super(props);
this.state = {
email : "",
password : ""
};
this.storeEmail = this.storeEmail.bind( this );
this.storePassword = this.storePassword.bind( this );
}
storeEmail(e){
this.setState({ email : e.target.value });
}
storePassword(e){
this.setState({ password : e.target.value });
}
handleSignUp(){
this.props.handleSignUp(this.state);
}
render(){
return(
<div className="pageContainer">
<form action="" method="post">
<InputField labelClass = "label"
labelText = "Username"
inputId = "signUp_username"
inputType = "email"
inputPlaceholder = "registered email"
inputClass = "input" />
<Button btnClass = "btnClass"
btnLabel = "Submit"
onClickEvent = { handleSignUp } />
</form>
</div>
);
}
}
);
Or Is it not recommended & I should not create custom child components within the form?
child component => InputField
import React,
{ Component } from "react";
export class InputField extends Component{
constructor( props ){
super( props );
this.state = {
value : ""
};
this.onUserInput = this.onUserInput.bind( this );
}
onUserInput( e ){
this.setState({ value : e.target.value });
this.props.storeInParentState({[ this.props.inputType ] : e.target.value });
}
render(){
return <div className = "">
<label htmlFor = {this.props.inputId}
className = {this.props.labelClass}>
{this.props.labelText}
</label>
<input id = {this.props.inputId}
type = {this.props.inputType}
onChange = {this.onUserInput} />
<span className = {this.props.validationClass}>
{ this.props.validationNotice }
</span>
</div>;
}
}
Error : I get the error e.target is undefined on the parent storeEmail func.
React's one-way data-binding model means that child components cannot send back values to parent components unless explicitly allowed to do so. The React way of doing this is to pass down a callback to the child component (see Facebook's "Forms" guide).
class Parent extends Component {
constructor() {
this.state = {
value: ''
};
}
//...
handleChangeValue = event => this.setState({value: event.target.value});
//...
render() {
return (
<Child
value={this.state.value}
onChangeValue={this.handleChangeValue}
/>
);
}
}
class Child extends Component {
//...
render() {
return (
<input
type="text"
value={this.props.value}
onChange={this.props.onChangeValue}
/>
);
}
}
Take note that the parent component handles the state, while the child component only handles displaying. Facebook's "Lifting State Up" guide is a good resource for learning how to do this.
This way, all data lives within the parent component (in state), and child components are only given a way to update that data (callbacks passed down as props). Now your problem is resolved: your parent component has access to all the data it needs (since the data is stored in state), but your child components are in charge of binding the data to their own individual elements, such as <input> tags.
Addendum
In response to this comment:
What if we render a list of the child component? Using this single source of truth in Lifting state up technique will let the parent controls all the state of all the child inputs right? So how can we access each of the value input in the child component to (which is rendered as list) from the parent component?
For this case, you may map a child component for each element in the list. For example:
class Parent extends Component {
//...
handleChangeListValue = index => event => {
this.setState({
list: this.state.list
.map((element, i) => i === index ? event.target.value : element)
});
}
//...
render() {
return this.state.list.map((element, i) => (
<Child
value={element}
onChangeValue={this.handleChangeListValue(i)}
/>
));
P.S. Disclaimer: above code examples are only for illustrative purposes of the concept in question (Lifting State Up), and reflect the state of React code at the time of answering. Other questions about the code such as immutable vs mutable array updates, static vs dynamically generated functions, stateful vs pure components, and class-based vs hooks-based stateful components are better off asked as a separate question altogether.
React class component
Parent.js
import React, { Component } from 'react';
import Child from './child'
class Parent extends Component {
state = {
value: ''
}
onChangeValueHandler = (val) => {
this.setState({ value: val.target.value })
}
render() {
const { value } = this.state;
return (
<div>
<p> the value is : {value} </p>
<Child value={value} onChangeValue={this.onChangeValueHandler} />
</div>
);
}
}
export default Parent;
Child.js
import React, { Component } from 'react';
class Child extends Component {
render() {
const { value , onChangeValue } = this.props;
return (
<div>
<input type="text" value={value} onChange={onChangeValue}/>
</div>
);
}
}
export default Child;
React hooks
Parent.js
import { useState } from "react";
import Child from "./child";
export default function Parent() {
const [value, changeValue] = useState("");
return (
<div>
<h1>{value}</h1>
<Child inputValue={value} onInputValueChange={changeValue} />
</div>
);
}
Child.js
export default function Child(props) {
return (
<div>
<input
type="text"
value={props.inputValue}
onChange={(e) => props.onInputValueChange(e.target.value)}/>
</div>
);
}
Parent.js
import SearchBar from "./components/SearchBar";
function App() {
const handleSubmit = (term) => {
//Log user input
console.log(term);
};
return (
<div>
<SearchBar onPressingEnter={handleSubmit} />
</div>
);
}
export default App;
Child.js
import { useState } from "react";
function SearchBar({ onPressingEnter }) {
const [UserSearch, setname] = useState("[]");
/* The handleChange() function to set a new state for input */
const handleChange = (e) => {
setname(e.target.value);
};
const onHandleSubmit = (event) => {
//prevent form from making a http request
event.preventDefault();
onPressingEnter(UserSearch);
};
return (
<div>
<form onSubmit={onHandleSubmit}>
<input
type="search"
id="mySearch"
value={UserSearch}
onChange={handleChange}
name="q"
placeholder="Search the siteā€¦"
required
/>
</form>
</div>
);
}
export default SearchBar;
You can add a "ref name" in your InputField so you can call some function from it, like:
<InputField
ref="userInput"
labelClass = "label"
labelText = "Username"
inputId = "signUp_username"
inputType = "email"
inputPlaceholder = "registered email"
inputClass = "input" />
So you can access it using refs:
this.refs.userInput.getUsernamePassword();
Where getUsernamePassword function would be inside the InputField component, and with the return you can set the state and call your props.handleSignUp

Categories

Resources