There is parent component which have handleChange function, I pass to the child that function.
And provide to the input fileds, then there is bug with input fileds, I am not able to change values at all.
ParentComp:
handleChange = (e, data) => {
if (data && data.name) {
this.props.setFieldValue(data.name, data.value)
if (data.name === 'pay_rate') {
console.log('PAY_RATE: ', data)
}
}
}
return (
<Grid.Column width={8}>
<Segment raised>
<Header>
<p style={{ fontSize: '1.2rem' }}>
Church Mutual Worker\'s Compensation Claim
<span style={{ float: 'right' }}>{`Claim #${props.claim.claimNumber}`}</span>
</p>
</Header>
<Form onSubmit={handleSubmit}>
// Here called is Child component
<EditStandaloneClaimDetails
claim={props.claim}
loading={loading}
handleChange={props.handleChange}
/>
</Form>
<Comment currentClaim={props.currentClaim} />
</Segment>
</Grid.Column>
)
ChildComponent:
const EditStandaloneClaimDetails = ({ handleChange, claim, loading, testChange }) => {
if (!claim || loading) {
return null
}
const { noticeOnly, recieveDate, accountNumber } = claim
return (
<Segment
raised
style={{
backgroundColor: '#F0F0F0',
}}
>
<h5>Claim Details</h5>
<Form.Group >
<Form.Field>
// CANNOT ENTER A NEW VALUE FOR DATE INPUT FILED
<label>Date Received</label>
<DateInput
name={'recieveDate'}
placeholder="Date received"
value={recieveDate}
onChange={handleChange}
style={{ width: '65%' }}
dateFormat={'MM/DD/YYYY'}
/>
</Form.Field>
</Form.Group >
Maybe problem is in this attribute value={recieveDate}?
You can handle it using call back function.
In your parent component replace below lines:
handleChange = (e, data) => {
//here you get the updated date
//add your logic
}
// Here called is Child component
<EditStandaloneClaimDetails
recieveDate = {'your date'}
claim={props.claim}
loading={loading}
handleChange={(event, data) =>this.handleChange(event,data)}
/>
In Child component add below function, that function is responsible to call back to parent component.
constructor(props){
super();
this.state = { recieveDate: prop.recieveDate };
}
HandleChange(event,value){
this.setState({ recieveDate})
this.props.handleChange(value,event.uid);
}
<DateInput
name={'recieveDate'}
placeholder="Date received"
value={recieveDate}
onChange={(event, value) =>this.HandleChange(event,data)}
style={{ width: '65%' }}
dateFormat={'MM/DD/YYYY'}
/>
Related
How do i pass a validation value from child component to parents component?
i tried to use props but it didn't work . i tried to pass the 'isValidValue' status
Child Component :
function MilikSendiri({isValidValue}) {
const { register, handleSubmit } = useForm()
function sweetAlertclick(){
Swal.fire({
icon: 'success',
title: 'Data anda sudah tersimpan ',
})
}
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
// validateOnMount
>
{
formik => {
const isValidValue = formik.isValid? ("Data Completed") : ("DData incomplete");
return(
<div>
<div>
Status : {isValidValue}
<label htmlFor="luasTanah"> Luas Tanah </label>
<Field className="formBiodata"
type="text" id="outlined-basic"
placeholder="luasTanah"
fullWidth
id="luasTanah"
name="luasTanah"
margin="normal" variant="outlined"
/>
<ErrorMessage name='luasTanah' component={TextError}/>
</div>
<div>
<label htmlFor="BiayaPBB"> Biaya PBB </label>
<Field className="formBiodata"
type="text" id="outlined-basic"
placeholder="BiayaPBB"
fullWidth
id="BiayaPBB"
name="BiayaPBB"
margin="normal" variant="outlined"
/>
<ErrorMessage name='BiayaPBB' component={TextError}/>
</div>
<Button onClick={sweetAlertclick} type ="submit"
variant="contained" startIcon={<SaveIcon />} color="primary" style={{
marginLeft: '25rem', marginTop: '20px', width: '20rem', height: 45,
fontSize: 22, backgroundColor: '#22689F'}}
disabled={!formik.isDirty && !formik.isValid} >Simpan
</div>
)
}
}
</Formik>
)
}
Parent Component :
function UKTRumah ({isValidValue}) {
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
// validateOnMount
>
{
formik => {
console.log('Formik props', formik)
return(
<div className ="IsiBiodata">
<Accordion square expanded={expanded === 'panel1'} onChange=.
{handleChange('panel1')} style={{marginLeft: '15rem', marginRight:
'15rem', marginTop: '3rem'}}>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-
header">
<PersonIcon/>
<Typography> Data Rumah</Typography>
<Typography}> { isValidValue }
</Typography>
</AccordionSummary>
<AccordionDetails>
<div className ="IsiBiodata">
<Form>
</div>
</Form>
</div>
</AccordionDetails>
</Accordion>
</div>
)}}
</Formik>
)}
Thank you
Your example code seems to be lacking some key lines to answer the question specifically.
However, generally if it is data that Parent should be aware of, but that the child will make use of, it should be a value of state in the parent, then handed to the child as props. Here's a very small example using functional components:
const Child = ({ formik, setIsValid, isValid }) => {
useEffect(() => {
setIsValid(formik.isValid)
}, [formik.isValid]);
return <input />;
}
const Parent = () => {
const [isValid, setIsValid] = useState(true);
return <Child isValid={isValid} setIsValid={setIsValid} />
}
You can hold the value on your parent and pass a function to change it to your child. I can't really show you that with the code you posted, but I can show an example of what I mean. The parent has a state with an update function setIsValid and passes that to the child. The child can call setIsValid and that will update the isValid value on the parent.
parent
function Parent() {
const [isValid, setIsValid] = useState(false);
return <div>
<Child setIsValid={setIsValid} />
IsValid {isValid}
</div>
}
child
function Child({ setIsValid }) {
return <button onClick={() => setIsValid(true)}>Set Valid</button>
}
I am using Codesandbox to work on learning React. I am trying to conditionally render a functional React component inside of a function (inside of a class based component), that fires when a button is clicked.
Here is the link to the Codesandbox: https://codesandbox.io/embed/laughing-butterfly-mtjrq?fontsize=14&hidenavigation=1&theme=dark
The issue I have is that, without importing and rendering the Error and Meals in App.js, I never can get either component to render from the Booking component. In the function here:
if (!this.state.name) {
return (
<div>
<Error />
</div>
);
}
else {
return <Meals name={this.state.name} date={this.state.date} />;
}
}
I should be rendering Error, which should then show on the screen on click if no name is inputted but nothing happens and I am stumped.
Is there anything obvious that would be preventing me from seeing the Error component from loading on the click?
Thank you in advance!
Everything that is displayed on the screen comes from render method. You cann't return JSX from any function like that. You can do something like this:
class Bookings extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
date: "",
display: false
};
}
guestInfoHandler = event => {
console.log(this.state, "what is the state");
this.setState({ name: event.target.value });
};
dateInfoHandler = event => {
this.setState({ date: event.target.value });
};
showMeals = () => {
this.setState({ display: true });
};
render() {
return (
<>
<div style={{ display: "inline-block" }}>
<form
className="theForm"
style={{
height: "50px",
width: "100px",
borderColor: "black",
borderWidth: "1px"
}}
>
<label className="theLabel">
Name:
<input
className="theInput"
type="text"
placeholder="guest name here"
onChange={this.guestInfoHandler}
value={this.state.value}
/>
</label>
</form>
<form>
<label>
Date:
<input
type="text"
placeholder="date here"
onChange={this.dateInfoHandler}
value={this.state.value}
/>
</label>
</form>
<button onClick={() => this.showMeals()}>Click</button>
</div>
{ display && name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</>
);
}
}
export default Bookings;
Hope this works for you.
render() {
const name = this.state.name;
return (
<div>
{name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</div>
);
}
nb:use render method in class component only.
there is various types conditional rendering mentioned in
https://reactjs.org/docs/conditional-rendering.html#
I have small portion of my app rendering a dropdown selection so users can view some brief information about library versions within the app.
The first dropdown is for the user to pick what they want view, for brevity I just added the relevant option for this question.
The second dropdown renders a fetched list of numbers pertaining to deviceIds. These deviceIds are fetched from a child class and then passed via props up to the parent class.
Now, In Semantic-UI-React, they have a dropdown module with a clearable prop which I am using on this dropdown populated with deviceIds. Below in VersionNumber class, you can see the props defined for the aforementioned dropdown.
The clearable prop lets the user remove the selected input from the dropdown. However, in my app when the input is removed it calls the onChange function which I do not want. I tried passing a custom change function to the clearable prop where I'm attempting to reset the state variable deviceId back to a undefined value if it's "cleared" by the user.
Is this possible? I'm pretty sure I'm taking the correct approach, but may be having an issue where the onChange function is firing before the clearable passed function.
I have a codesandbox that reproduces this problem here.
import React, { Component } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import {
Dropdown,
Form,
Divider,
Input,
Message,
Loader
} from "semantic-ui-react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
viewSelection: "",
deviceId: "",
versionNum: "",
isLoading: true
};
}
handleViewSelection = (e, { value }) => {
this.setState({ viewSelection: value }, () => {
console.log("view election --> ", this.state.viewSelection);
});
};
onDeviceIdChange = async (e, { value }) => {
console.log("device id value -->", value);
this.setState({ deviceId: value }, () => {
console.log(
"deviceId value updated to state on select -->",
this.state.deviceId
);
});
try {
const { data } = await axios.get(`/deviceId/${value}`);
const version = data.data.versionNumber;
this.setState({ versionNum: version.version, isLoading: false }, () => {
console.log("callback from admin version fetch", this.state.versionNum);
});
} catch (error) {
console.error(Error(`Error getting the selected deviceId ${error.message}`));
}
};
handleClear = () => {
this.setState({ deviceId: "" }, () => {
console.log("handleClear function fired");
});
};
render() {
const { viewSelection, deviceId, versionNum, isLoading } = this.state;
return (
<div
style={{ display: "flex", minHeight: "100vh", flexDirection: "column" }}
>
<div style={{ flex: 1 }}>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
flex: "1"
}}
>
<div style={{ width: "1000px" }}>
<Divider style={{ marginTop: "7em" }} horizontal>
View Data
</Divider>
<Message style={{ marginTop: "2em" }} info>
<Message.Header>
Want to see more specific information? Log in
here.
</Message.Header>
</Message>
<Form.Field style={{ marginTop: "2em" }}>
<label>Select data to view</label>
<Dropdown
scrolling
placeholder="Pick an option"
value={viewSelection}
fluid
selection
multiple={false}
search
options={viewOptions}
onChange={this.handleViewSelection}
/>
</Form.Field>
{this.state.viewSelection && (
<div style={{ marginTop: "2em" }}>
{viewSelection && viewSelection === "versionNumber" ? (
<>
<VersionNumber
onDeviceIdChange={this.onDeviceIdChange}
deviceId={deviceId}
handleClear={this.handleClear}
/>
<div>
<label style={{ display: "block", marginTop: "2em" }}>
Version Number
</label>
{isLoading ? (
<Loader active inline="centered" />
) : (
<Input value={versionNum} fluid readOnly />
)}
</div>
</>
) : null}
</div>
)}
</div>
</div>
</div>
</div>
);
}
}
class VersionNumber extends Component {
constructor(props) {
super(props);
this.state = {
deviceId: "",
deviceIds: []
};
}
async componentDidMount() {
await this.getDeviceIds();
}
getDeviceIds = async () => {
try {
const { data } = await axios.get("/deviceIds");
console.log("device IDs --> ", data);
const deviceIds = data.data.deviceIds;
this.setState(
{
deviceIds: deviceIds
},
() => {
console.log(
"setState callback with updatesd deviceIds state -->",
this.state.deviceIds
);
}
);
} catch (error) {
console.error(Error(`Error getting deviceIds: ${error.message}`));
}
};
render() {
const { onDeviceIdChange, deviceId, handleClear } = this.props;
const { deviceIds } = this.state;
return (
<Form.Field required>
<label style={{ display: "block" }}>Device Id</label>
<Dropdown
id="deviceId"
value={deviceId}
onChange={onDeviceIdChange}
selection
fluid
placeholder="Please select an device id"
clearable={handleClear}
options={deviceIds.map(id => {
return {
text: id.id,
value: id.id,
key: id.id
};
})}
style={{ marginTop: ".33", marginBottom: "2em" }}
/>
</Form.Field>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
clearable prop expects a boolean value. You can change your onChange callback to consider the scenario where the value is going to be passed in as null / undefined
The function can be modified as below to reset the deviceId and prevent the API call
onDeviceIdChange = async (e, { value }) => {
// VALUE WILL BE PASSED IN AS "" WHEN THE CLEAR OPTION IS CLICKED
console.log("device id value -->", value);
this.setState({ deviceId: value }, () => {
console.log(
"deviceId value updated to state on select -->",
this.state.deviceId
);
});
// THIS IS THE CONDITION TO CATCH THE CLEARABLE INVOCATION
if(!value) {
this.handleClear();
return;
}
...
};
if(!value) return; Think of this condition as the execution that the clearable option will invoke. You can invoke anything before the return to ensure that your application handles the clear option in the way you expect it to.
How do i accept conditional attributes in react.js
below is my search component, I want the InputGroup to have a onSubmit attribute if the onSubmit function is passed and an onChange attribute if an onChange function is passed
class QueryBar extends PureComponent {
render() {
const { placeholder, leftIcon, onSubmit, onChange, width } = this.props;
return (
<form
style={{ width }}
onSubmit={e => {
e.preventDefault();
onSubmit(e.target[0].value);
}}
>
<InputGroup
placeholder={placeholder}
width={width}
leftIcon="search"
rightElement={
<Button
type="submit"
icon={leftIcon}
minimal={true}
intent={Intent.PRIMARY}
/>
}
/>
</form>
);
}
}
QueryBar.propTypes = {
width: PropTypes.number,
placeholder: PropTypes.string,
leftIcon: PropTypes.oneOfType(['string', 'element']),
onSubmit: PropTypes.func
};
QueryBar.defaultProps = {
placeholder: 'Search...',
leftIcon: 'arrow-right',
width: 360
};
export default QueryBar;
jsx elements can also accept objects. Initialize an object that contains information for both situations and then add a conditional to add a function if it exists in the props passed in.
render() {
const { placeholder, leftIcon, onSubmit, onChange, width } = this.props;
const inputGroupProps = {
placeholder,
width,
leftIcon: 'search',
rightElement: (
<Button
type="submit"
icon={leftIcon}
minimal={true}
intent={Intent.PRIMARY}
/>
)
}
if (onChange) {
inputGroupProps.onChange = onChange
}
if (onSubmit) {
inputGroupProps.onSubmit = onSubmit
}
return (
<form
style={{ width }}
onSubmit={e => {
e.preventDefault();
onSubmit(e.target[0].value);
}}
>
<InputGroup {...inputGroupProps} />
</form>
);
}
While I do not recommend it, adding both are technically OK because a prop that isn't passed in from the parent but destructured, will be undefined. I don't recommend this because it is not expressive and will probably confuse you in the future
<InputGroup
placeholder={placeholder}
width={width}
leftIcon="search"
rightElement={
<Button
type="submit"
icon={leftIcon}
minimal={true}
intent={Intent.PRIMARY}
/>
}
onChange={onChange} // will be undefined and have no behavior if parent does not pass an onChange prop
onSubmit={onSubmit} // same for this one
/>
You can pass null if its not there i.e :
<InputGroup
placeholder={placeholder}
width={width}
leftIcon="search"
onChange={onChangeFn?onChangeFn:null}
onSubmit={onSubmitFn ? onSubmitFn : null}
rightElement={
<Button
type="submit"
icon={leftIcon}
minimal={true}
intent={Intent.PRIMARY}
/>
}
/>
It will make sure if function is there then call function otherwise it will not anything.
I would do this:
The idea is to have an Object optionalProps, an empty object for any possible conditional properties, when a property exists, we add it to the object, then, in the InputGroup component we apply it as {...optionalProps} which will extract any added properties to the object, and return nothing if null.
we could follow another approach: onChange={onChange && onChange}
But, note This will return false as a value for cases where onChange doesn't exist.
render() {
const { placeholder, leftIcon, onSubmit, onChange, width } = this.props;
let optionalProps = {};
if(onChange){
optionalProps['onChange'] = onChange;
}
if(onSubmit){
optionalProps['onSubmit'] = onSubmit;
}
return (
<form
style={{ width }}
onSubmit={e => {
e.preventDefault();
onSubmit(e.target[0].value);
}}
>
<InputGroup
placeholder={placeholder}
width={width}
leftIcon="search"
{...optionalProps}
rightElement={
<Button
type="submit"
icon={leftIcon}
minimal={true}
intent={Intent.PRIMARY}
/>
}
/>
</form>
);
}
I have a form that has 10+ input fields that update the state of the class. To make things look cleaner I moved all input fields with labels into a separate component so I could re-use it for each input instead. This component takes 2 parameters and serves as a child in my main class.
child component:
const Input = ({ name, placeholder }) => {
return (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}><Form.Label>{ name }</Form.Label></Col>
<Col sm="5"><Form.Control placeholder={ placeholder }/></Col>
</Row>
</div>
)
}
parent:
state = { name: '', description: '' }
handleSubmit = (e) => {
e.preventDefault()
console.log(this.state);
}
render(){
return(
<Form style={{ marginBottom: "5%", padding: 10 }} onSubmit={ this.handleSubmit } >
<Input name="Name: " placeholder="How is it called?" onChange={ (event) => this.setState({name: event.target.value}) }/>
<Input name="Description: " placeholder="Please describe how does it look like?" onChange={ (event) => this.setState({description: event.target.value}) }/>
<Button variant="outline-success" size="lg" type="submit" >SUBMIT</Button>
</Form>
)
}
After I did that I can't find the way how to update the state from my child components when the text is changed. All my attempts to do so either crashed the website or did nothing. I am still new to React.js so any feedback is appreciated.
Pass onChange event to your child component and wire it with Form.Control control.
Your Input component will be,
const Input = ({ name, placeholder, onChange }) => {
return (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}>
<Form.Label>{name}</Form.Label>
</Col>
<Col sm="5">
<Form.Control onChange={onChange} placeholder={placeholder} />
</Col>
</Row>
</div>
);
};
And your Parent component is,
class Parent extends React.Component {
state = { name: "", description: "" };
handleSubmit = e => {
e.preventDefault();
console.log(this.state);
};
render() {
return (
<Form
style={{ marginBottom: "5%", padding: 10 }}
onSubmit={this.handleSubmit}
>
<Input
name="Name: "
placeholder="How is it called?"
onChange={event => this.setState({ name: event.target.value })}
/>
<Input
name="Description: "
placeholder="Please describe how does it look like?"
onChange={event => this.setState({ description: event.target.value })}
/>
<Button variant="outline-success" size="lg" type="submit">
SUBMIT
</Button>
</Form>
);
}
}
Working Codesandbox here.
In React, properties flow from the parent component to the child component, so you cannot directly "pass" the state from the child to the parent.
What you can do however is to have the parent pass a callback function to the child that will be called to update the parent's state.
Here is an example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
};
}
updateName(name) {
if (name === this.state.name) return;
this.setState({ name });
}
render() {
return (
<div>
<p>The name is {this.state.name}</p>
<ChildComponent handleNameUpdate={name => this.updateName(name)} />
</div>
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
};
}
handleInputChange(e) {
this.setState({ name: e.target.value });
this.props.handleNameUpdate(e.target.value)
}
render() {
return <input type="text" value={this.state.name} onChange={e => this.handleInputChange(e)} />;
}
}
You have to build what is known as a controlled component.
const Input = ({ label, name, onChange, placeholder }) => (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}>
<Form.Label>{ label }</Form.Label></Col>
<Col sm="5">
<Form.Control name={ name }
value={ value }
placeholder={ placeholder }
onChange={ onChange }
/>
</Col>
</Row>
</div>
)
And in your parent,
state = { name: '', description: '' }
handleChange = ({ target: { name, value } }) => this.setState({ [name]: value })
render() {
const { name, description } = this.state
<Form style={{ marginBottom: "5%", padding: 10 }} onSubmit={ this.handleSubmit } >
<Input label="Name: " name="name" value={name} onChange={handleChange}/>
<Input label="Description: " description="description" value={description} onChange={handleChange}/>
<Button variant="outline-success" size="lg" type="submit" >SUBMIT</Button>
</Form>
}
Advice
Try to avoid manufacturing lambda methods inside the render function as much as possible and have a class property as a lambda method so that lambdas do not need to be manufactured on every render cycle.