Parent.js
import React, { useState } from 'react'
import Child from './Child'
const Parent = () => {
const[data,setData] = useState('')
const[name,setName] = useState('')
const[toggled,setToggled] = useState(false)
const[age,setAge] = useState('')
const ageToChild = (ageData) =>{
setAge(ageData)
}
const childToParent = (childData) =>{
setData(childData)
}
const handleSubmit = (e) =>{
e.preventDefault()
alert(`Age is ${age} , Form Submitted`)
console.log(`Name is ${name} and Age is ${age}`)
}
return (
<>
{data}
<div>
{/* <Child childToParent={childToParent}></Child> */}
<form onSubmit={handleSubmit}>
<label>Name : </label>
<input type="text" value={name} onChange={(e)=>setName(e.target.value)}></input>
<button type='button' onClick={()=>setToggled(!toggled)}>Age ?</button>
{toggled && <Child childToParent={childToParent} ageToChild={ageToChild}></Child>}
<button type='button'>Submit</button>
</form>
</div>
</>
)
}
export default Parent
Child.js
import React from 'react'
const Child = ({childToParent,ageToChild}) => {
const data = "This is some data from the child component to parent"
// const age = ageToChild
return (
<>
<button onClick={()=>childToParent(data)}>Click Child</button>
<label>Age : </label>
<input type='text' onChange={()=>ageToChild()}></input>
</>
)
}
export default Child
I am getting output as Name is inputtedname and Age is Undefined , How do I get the user inputted age value logged in the console?
I am trying to pass data from child to parent using functional components
If you want to pass age value to alert() from Child.js component, you should add e.target.value to onChange:
<input type='text' onChange={(e)=>ageToChild(e.target.value)}></input>
Make sure to pass the ageToChild function from the parent component to the child:
<Child childToParent={childToParent} ageToChild={ageToChild} />
Then from the Child component you can simply do:
<input type='text' onChange={(e)=> ageToChild(e.target.value)} />
use this code:
<input type='text' onChange={(e)=>ageToChild(e.target.value)}></input>
You have forgotten to pass the value in the function😁. Try passing it in onChange.
onChange={(e)=>ageToChild(e.target.value)}
Related
So I have a parent component which contains a form and a child component(this component also has a form , here its a dynamic form meaning when the add button is hit it creates another form below so that user can add a list of parameters of various types . Basically I am trying to achieve state lifting from child to component . I would be really grateful if someone could help me out , I have been stuck on this since a week and I tried a lot . I would appreciate if someone could refactor my code so that it works . I have also attached a gif which shows the form
GIF : https://drive.google.com/file/d/15YXGhvo0OMCh4ch44q4S88wcqOB7i2ew/view?usp=sharing
Parent Component - ParamsForm.js
import React, { useState, useEffect } from 'react'
import { Form } from 'react-bootstrap'
import styles from '../style.module.css'
import Operations from './Operations'
import OperationsFormTest from './OperationsFormTest'
const ParamsForm = () => {
const[isToggled,setIsToggled] = useState(false)
const[formData,setFormData] = useState(
{url:'',endpoint:'',name:'',description:'',type:'',required:''}
)
const handleSubmit = (e) =>{
e.preventDefault()
console.log('Form Data is :' , formData)
}
const handleChangeInput = (index,e) =>{
const values = [...formData]
values[index][e.target.name] = e.target.value
setFormData(values)
}
const handleAddFields = () =>{
setFormData([...formData,{url:'',endpoint:'',name:'',description:'',type:'',required:''}])
}
const handleRemoveFields = (index) =>{
const values = [...formData]
values.splice(index,1)
setFormData(values)
}
useEffect(()=>{
console.log(isToggled)
},[isToggled])
return (
<div className={styles.paramFormsContainer}>
{setFormData}
<form onSubmit={handleSubmit}>
<input type='text' name='url' placeholder='Url..' value={formData.url} onChange={handleChangeInput}></input>
<input type='text' name='endpoint' placeholder='Endpoint...' value={formData.endpoint} style={{flex : 1 }} onChange={handleChangeInput}></input>
<button type='button' onClick={()=>setIsToggled(!isToggled)} className={styles.pathParamFormsBtn}>Path Params</button>
{isToggled && <OperationsFormTest name={formData.name} description={formData.description} type={formData.type} required={formData.required} handleAddFields={handleAddFields} nameFunc={handleChangeInput} descriptionFunc={handleChangeInput} typeFunc={handleChangeInput} requiredFunc={handleChangeInput} handleRemoveFields={handleRemoveFields}></OperationsFormTest>}
<br></br><br></br>
<button type='submit' onClick={handleSubmit}>Submit</button>
</form>
</div>
)
}
export default ParamsForm
Child Component - OperationsFormTest.js
import React, { useEffect, useState } from 'react'
import styles from '../style.module.css'
import {FaInfo,FaFileInvoiceDollar} from 'react-icons/fa'
import ReactTooltip from "react-tooltip";
const OperationsFormTest = ({name,type,description,required,nameFunc,descriptionFunc,typeFunc,requiredFunc,handleAddFields,handleRemoveFields}) =>{
const ChildToParentName = (e) =>{
nameFunc(e)
}
const ChildToParentType = (e) =>{
typeFunc(e)
}
const ChildToParentDescription = (e) =>{
descriptionFunc(e)
}
const ChildToParentRequired = (e) =>{
requiredFunc(e)
}
return(
<>
<div>
<div className={styles.pathParamsFormParentContainer}>
<div className={styles.pathParamsFormChildContainer}>
<label>Name : </label>
<input name='name' type='text' placeholder='Name..' value={name} onChange={ChildToParentName}></input><br></br><br></br>
<label>Description : </label>
<input name='description' type='text' placeholder='Description..' value={description} onChange={ChildToParentDescription}></input><br></br><br></br>
<select name = 'type' value = {type} onChange={ChildToParentType}>
<option>Any</option>
<option>String</option>
<option>Boolean</option>
</select>
<label>Required : </label>
<input name='required' type='text' placeholder='Yes or No..' value={required} onChange={ChildToParentRequired}></input><br></br><br></br>
<button type='button' onClick={()=>handleAddFields()}>Add</button>
<button type='button' onClick={()=>handleRemoveFields()}>Remove</button><br></br><br></br>
</div>
</div>
</div>
</>
)
}
export default OperationsFormTest
I hope you will get some idea from this simple codes.
function Home() {
// Async await is up to you
const onSubmit = async (data)=> {
console.log(data);
}
return (
<Form onSubmit={onSubmit} />
)
}
function Form() {
const [text,setText] = useState("");
// async await is up to you
const handleSubmit = async (e)=> {
e.preventDefault();
await onSubmit(text);
setText("");
}
return (
<form onSubmit={handleSubmit}>
<input type={"text"} value={text} onChange={e=>setText(e.target.value)} />
<input type={"submit"} />
</form>
)
}
I'm trying to render a component as a child passing the parent props, but page doesn't show anything, just white. When I take out the part of the code that uses the props, it renders. I'm trying to pass a state var and a function. Thanks :)
const MainButtons = (props) => {
const { depositAmount } = props;
return (
<div className="container1">
<form
className="deposit"
onSubmitCapture={(event) => {
event.preventDefault();
const depositAmount = depositAmount;
props.deposit(depositAmount);
}}
>
<input
type="text"
className="inputs"
placeholder="Amount to deposit"
ref={(input) => (depositAmount = input)}
/>
<button className="btnS btnS-colored">
<BsArrowBarUp />
Send
</button>
</form>
</div>
);
};
And the parent renders this:
<MainButtons
depositAmount={this.state.depositAmount}
deposit={this.deposit}
/>
How to transfer props from one sibling to another, please?
In main app I have only 2 siblings:
Input:
import React from "react";
const Input = () => {
return (
<>
<label htmlFor="name">Full Name</label>
<input type="text" id="name" placeholder="TheDareback" />
<label htmlFor="job">Job Title</label>
<input type="text" id="job" placeholder="Frontend Developer" />
</>
);
};
export default inputDetails;
Preview:
import React from "react";
const Preview = () => {
return (
<>
<table>
<thead>
<tr>
<th>{/* here I need a Full Name from the input */}</th>
<th>{/* here I need a Job Title from the input*/}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
I tried to add useEffect to Preview to read the value of each input.
for example
const name = document.querySelector("#name");
const [inputName, setInputName] = useState("TheDareback");
useEffect(() => (name.value ? setInputName(name.value) : null));
But I'm still getting an error:
Preview.js:9 Uncaught TypeError: Cannot read properties of null (reading 'value')
Is it possible to run useEffect only during the second rendering? Alternatively, is there another option than to move the props directly from Input.js where would I create a handler for each onChange in input?
Thank you very much for heading in the right direction.
Keep the state in the App component and give setter to Input and state to Preview component.
App.js
import Input from "./Input";
import Preview from "./Preview";
export default function App() {
const [state, setState] = useState({ name: "", job: "" });
return (
<div className="App">
<Input setState={setState} />
<Preview state={state} />
</div>
);
}
Input.js
import React from "react";
const Input = ({ setState }) => {
const onChangeHandler = (e) => {
setState((prevState) => ({
...prevState,
[e.target.id]: e.target.value
}));
};
return (
<>
<label htmlFor="name">Full Name</label>
<input
type="text"
id="name"
placeholder="TheDareback"
onChange={onChangeHandler}
/>
<label htmlFor="job">Job Title</label>
<input
type="text"
id="job"
placeholder="Frontend Developer"
onChange={onChangeHandler}
/>
</>
);
};
export default Input;
Preview.js
import React from "react";
const Preview = ({ state: { name, job } }) => {
return (
<>
<table>
<thead>
<tr>
<th>{name}</th>
<th>{job}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
Code Sandbox
You need some sort of a container component (or App.js for example), you can have an input state there, and an inputHandler function to pass to the Input component and put it with an onChange for example.
import React, {useState} from 'react';
export default function Container() {
const [input, setInput] = useState({
name: '',
job: ''
})
const inputHandler = (e, type) => {
setInput(prevState => ({...prevState, [type]: e.target.value}))
}
return (
<>
<Input onInputChange={inputHandler} />
<Preview input={input} />
</>
);
}
Input:
const Input = ({onInputChange}) => {
return (
<>
<label htmlFor="name">Full Name</label>
<input type="text" id="name" placeholder="TheDareback" onChange={(e) => onInputChange(e, 'name')} />
<label htmlFor="job">Job Title</label>
<input type="text" id="job" placeholder="Frontend Developer" onChange={(e) => onInputChange(e, 'job')} />
</>
);
};
export default Input;
Preview:
const Preview = ({input}) => {
return (
<>
<table>
<thead>
<tr>
<th>{input.name}</th>
<th>{input.job}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
I'm sitting with this for a while and wondering if there is any possibility of passing the state from parent to child in this case?
I need this id to give input and label an unique id couse this component is used multiple times.
Thanks for any advice.
Parent:
<FileUpload key={el.id} parentCallback={this.callback(el.id)} id={el.id}/>
Child:
import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';
const FileUpload = ({ parentCallback }) => {
return (
<Fragment>
<form className="image__uploadForm" onSubmit={onSubmit}>
{this.props.id} // Causes error props undef
<div className='image__upload'>
<input
type='file'
className='input__uploadFile'
id='uploadFile'
accept="image/*"
onChange={onChange}
/>
<label className='input__uploadFile--label' htmlFor='uploadFile'>
{filename}
</label>
{!file ? (
null
) :
<input
type='submit'
value='Upload'
/>
}
</div>
</form>
</Fragment>
);
};
export default FileUpload;
As #ajobi said, this will not be defined in a functional component using the arrow syntax.
You can solve this three ways:
1. Use the rest syntax to gather all props except parentCallback into a variable called props:
const FileUpload = ({ parentCallback, ...props }) => {
...
{props.id}
2. Spread all props into their own variables:
const FileUpload = ({ parentCallback, id }) => {
...
{id}
3. Spread none of the variables and use the props object when using all props in your component:
const FileUpload = (props) => {
...
{props.id}
...
props.parentCallback
You can not pass your callback like this parentCallback={this.callback(el.id)} because it will be executed instantly by render.
You could try to pass in an error function like parentCallback={() => this.callback(el.id)} and call it in the submit function
Id is undefined because Id is a key word and will be not passed
Parent:
<FileUpload key={el.id} parentCallback={() => this.callback(el.id)} {...el}/>
Child:
import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';
const FileUpload = ({ parentCallback, id }) => {
const onSubmit = () => {
return parentCallback()
}
return (
<Fragment>
<form className="image__uploadForm" onSubmit={onSubmit}>
{id}
<div className='image__upload'>
<input
type='file'
className='input__uploadFile'
id='uploadFile'
accept="image/*"
onChange={onChange}
/>
<label className='input__uploadFile--label' htmlFor='uploadFile'>
{filename}
</label>
{file && <input type='submit' value='Upload'/>} //Tip: If you work with && you do not need to return null
</div>
</form>
</Fragment>
);
};
export default FileUpload;
Otherwise you can pass your function like:
Parent:
<FileUpload key={el.id} parentCallback={this.callback} {...el}/>
Child:
....
const FileUpload = ({ parentCallback, id }) => {
const onSubmit = () => {
return parentCallback(id)
}
return (....)
}
I am using a variable below.
var newInput = {
title: this.inputTitle.value,
entry: this.inputEntry.value
};
This is used by my input fields.
<input type="text" id="inputname" className="form-control" ref={el => this.inputTitle = el} />
<textarea id="inputage" ref={el => this.inputEntry = el} className="form-control" />
<button className="btn btn-info" onClick={this.sendthru}>Add</button>
Once I activate {this.sendthru} I want to clear my input fields. However, I am uncertain how to do so.
Also, as shown in this example, it was pointed out to me that I should use the ref property for input values. What I am unclear of is what exactly does it mean to have {el => this.inputEntry = el}. What is the significance of el in this situation?
Let me assume that you have done the 'this' binding of 'sendThru' function.
The below functions clears the input fields when the method is triggered.
sendThru() {
this.inputTitle.value = "";
this.inputEntry.value = "";
}
Refs can be written as inline function expression:
ref={el => this.inputTitle = el}
where el refers to the component.
When refs are written like above, React sees a different function object each time so on every update, ref will be called with null immediately before it's called with the component instance.
Read more about it here.
Declare value attribute for input tag (i.e value= {this.state.name}) and if you want to clear this input value you have to use this.setState({name : ''})
PFB working code for your reference :
<script type="text/babel">
var StateComponent = React.createClass({
resetName : function(event){
this.setState({
name : ''
});
},
render : function(){
return (
<div>
<input type="text" value= {this.state.name}/>
<button onClick={this.resetName}>Reset</button>
</div>
)
}
});
ReactDOM.render(<StateComponent/>, document.getElementById('app'));
</script>
I'm not really sure of the syntax {el => this.inputEntry = el}, but when clearing an input field you assign a ref like you mentioned.
<input type="text" ref="someName" />
Then in the onClick function after you've finished using the input value, just use...
this.refs.someName.value = '';
Edit
Actually the {el => this.inputEntry = el} is the same as this I believe. Maybe someone can correct me. The value for el must be getting passed in from somewhere, to act as the reference.
function (el) {
this.inputEntry = el;
}
I have a similar solution to #Satheesh using React hooks:
State initialization:
const [enteredText, setEnteredText] = useState('');
Input tag:
<input type="text" value={enteredText} (event handler, classNames, etc.) />
Inside the event handler function, after updating the object with data from input form, call:
setEnteredText('');
Note: This is described as 'two-way binding'
You can use input type="reset"
<form action="/action_page.php">
text: <input type="text" name="email" /><br />
<input type="reset" defaultValue="Reset" />
</form>
Now you can use the useRef hook to get some magic if you do not want to use the useState hook:
function MyComponent() {
const inputRef = useRef(null);
const onButtonClick = () => {
// #ts-ignore (us this comment if typescript raises an error)
inputRef.current.value = "";
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={onButtonClick}>Clear input</button>
</>
);
}
As I mentioned, if you are using useState that is the best way. I wanted to show you also this special approach.
Also after React v 16.8+ you have an ability to use hooks
import React, {useState} from 'react';
const ControlledInputs = () => {
const [firstName, setFirstName] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
if (firstName) {
console.log('firstName :>> ', firstName);
}
};
return (
<>
<form onSubmit={handleSubmit}>
<label htmlFor="firstName">Name: </label>
<input
type="text"
id="firstName"
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<button type="submit">add person</button>
</form>
</>
);
};
You can use useState:
import React, { useState } from 'react';
const [inputTitle, setInputTitle] = useState('');
then add value to your input component:
render() {
<input type="text" onChange={(e) => setInputTitle(e.target.value)}
value={inputTitle} />
<button onClick={handleSubmit} type="submit">Submit</button>
}
On your submit handler function:
setInputTitle('');
document.querySelector('input').defaultValue = '';
On the event of onClick
this.state={
title:''
}
sendthru=()=>{
document.getElementByid('inputname').value = '';
this.setState({
title:''
})
}
<input type="text" id="inputname" className="form-control" ref={el => this.inputTitle = el} />
<button className="btn btn-info" onClick={this.sendthru}>Add</button>
I used the defaultValue property, useRef, and onClick to achieve this.
let ref = useRef()
and then inside the return:
<input type="text" defaultValue="bacon" ref={ref} onClick={() => ref.current.value = ""} />
also if you want to use onChange for the input it wouldn't require any more configuration and you can just use it. If you want to have a dynamic defaultValue then you absolutely can, with useState.
A simple way to reset the input in React is by implementing the onBlur inside the input.
onBlur={cleanSearch}
ej:
const [search, setSearch] = useState('')
const handleSearch = ({target}) =>{
setSearch(target.value)
}
const cleanSearch = () =>setSearch('')
<input
placeholder="Search…"
inputProps={{ 'aria-label': 'search' }}
value={search}
onChange={handleSearch}
onBlur={cleanSearch}
/>
The way I cleared my form input values was to add an id to my form tag.
Then when I handleSubmit I call this.clearForm()
In the clearForm function I then use document.getElementById("myForm").reset();
import React, {Component } from 'react';
import './App.css';
import Button from './components/Button';
import Input from './components/Input';
class App extends Component {
state = {
item: "",
list: []
}
componentDidMount() {
this.clearForm();
}
handleFormSubmit = event => {
this.clearForm()
event.preventDefault()
const item = this.state.item
this.setState ({
list: [...this.state.list, item],
})
}
handleInputChange = event => {
this.setState ({
item: event.target.value
})
}
clearForm = () => {
document.getElementById("myForm").reset();
this.setState({
item: ""
})
}
render() {
return (
<form id="myForm">
<Input
name="textinfo"
onChange={this.handleInputChange}
value={this.state.item}
/>
<Button
onClick={this.handleFormSubmit}
> </Button>
</form>
);
}
}
export default App;