I have a functional SearchBar child component that is linked to the parent homepage. I pass it props of id and label from the parent component. The child component reads the props id and label as "undefined." I have this exact same code for another dropdown component and it works. My guess is that this may be because I am passing the props to a hoisted (above the functional component body) renderInput function? Can you pass props to a hoisted helper function? I am also using Redux Form, which I'm not sure if it complicates things. Input, which is a prop from Redux Form, works fine. This is my code:
//helper render function hoisted to prevent re-render of searchbar with every key stroke
const renderInput = ({ id, label input }) => {
return (
<div className="container position-relative" id={id}>
{label}
<input
{...input}
type="text"
placeholder="Search..."
className="py-4 px-5 border rounded-sm form-control"
/>
</div>
);
};
const SearchBar = ({ handleSubmit, submitSearch }) => {
const onSubmit = (formValues, dispatch) => {
submitSearch(formValues); //calls search action creator
dispatch(reset("SearchBar")); //clears search form after submission
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Field
name="search"
component={renderInput}
/>
</form>
);
}
This is the working code, if anyone else runs into the same issue. You have to pass the custom props of id and label to the Field component in Redux Form for the Redux Form component to read it.
<Field name="search" component={renderInput} id={id} label={label} />
Related
I have a component that implements a simle Formik form. The component also has listeners for an event generated by clicking on a LeafletJS map. I would like to be able to update the lat and lng fields whenever the event handler is called so that they can optionally be filled by clicking on the map instead of entering values directly.
import React, { useEffect } from 'react';
import { Formik, Form, Field } from 'formik';
const FormComponent = () => {
const onMapClick = e => {
console.log(e.detail.lat, e.detail.lng);
};
useEffect(() => {
document.addEventListener('map:click', onMapClick);
return () => {
document.removeEventListener('map:click', onMapClick);
};
}, []);
return (
<Formik
initialValues={{ username: 'guest', lat: 50.447243, lng: 30.524933 }}
onSubmit={values => { console.log(values); }}
>
{() => (
<Form id="test">
<Field type="text" name="username" />
<Field type="text" name="lat" />
<Field type="text" name="lng" />
<button type="submit">
Submit
</button>
</Form>
)}
</Formik>
);
};
export default FormComponent;
I have come across the Formik setFieldValue function but this only seems to be accessible from within the form. Likewise I cannot use UseEffect within the form function.
I have had some success by changing the intial values and using enableReinitialize but this resets other fields unless I keep track of all fields and update the initial values on each change.
What would be the recommended way of acheiving this? I should add that the code is a trimmed down example. The real form has way more fields.
This is how I would make this.
Imagine that you have component with form, component with map and some parent component that contain both of them.
I would use some useState in parent component that will handle change of selected lat and lng and provide this data to my form.
Then in form I'll use useEffect, so whenever those data is changed it will setFieldValue in form.
All this stuff will look like that (abstract example):
Parent component
const [coords, setCoords] = useState(null)
return (
<>
<Form coords={coords} />
<Map onChange={setCoords} />
</>
)
Form
useEffect(() => {
if(coords !== null) {
setFieldValue("lat", coords.lat)
setFieldValue("lng", coords.lng)
}
}, [coords])
This should work because setFieldValue can set values for fields in every moment of time, even after initialization. I'm not sure what problems have you had with useEffect and setFieldValue, so if my answer didn't helped you, provide some more code examples
I have child Component with input, and in the parent I've a button that disabled based on this input.
I thought about creating 'top level' state and pass the values like this:
const Parent = () => {
const [projectName, setProjectName] = useState('')
return (
<>
<Child projectName={projectName} setProjectName={setProjectName} />
<button disabled={projectName.length === 6}/>
</>
)
}
My question is, Is it solid react way to implement this?
In the child component I'm getting undefined for both projectName and setProjectName, why is it happening and how can I solve this?
Child Component:
const Child= ({projectName, setProjectName}) => {
return (
<>
<h2><StyledInlineSpan>Projects / </StyledInlineSpan>Create New Project</h2>
<Input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
</>
)
}
You shouldn't get an undefined, I think it is a problem with your Input component. I created a codesandbox with the same use case. As you type into the input, the Child component will change the state variable and the parent uses it.
It is completely fine to create a controlled Child component like this.
Seems like you have mis-spelled Input.
In React if the first letter of any HTML tag is capital, then it is treated as a custom React component.
Simply rename this
<Input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
to
<input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
Alright I am trying to submit two different forms as independent components in another page
component where I only have one button to submit the data of both forms.
So I am struggling to have a shared state in the page component and I need to pass the whole state of each form component to my page component on submit.
Can anyone recommend a best practice for my use case ?
render() {
return (
<div as={Row} className="container" style={formStyle}>
<Col>
<Form onSubmit={this.submitData}>
<TripForm />
<PostForm heading="add your first blog entry" />
<Button variant="dark" type="submit">
Summing up
</Button>
</Form>
</Col>
</div>
);
}
define your state in the parent component and pass it down in props
class PageComponent = {
state = { } //define your state here
handleChange = () => {} // define a function that handles changing state
submitData = () => {
// in here you can access this.state and then submit form data with that state
}
render() {
return (
<div as={Row} className="container" style={formStyle}>
<Col>
<Form onSubmit={this.submitData}>
<TripForm handleChange={handleChange} someState={someState} />
<PostForm heading="add your first blog entry" handleChange={handleChange} someState={someState}/>
<Button variant="dark" type="submit">
Summing up
</Button>
</Form>
</Col>
</div>
);
}
}
I've also defined someState which you can pass down as props to the child/form components. once you set state in there with handleChange it will set state in the parent component and you can submitData with that state
I have one grand-parent container where I have child component and inside that, another two child components.
This two child components are redux forms.
Now I want to handle both of these form submit events with form validations and perform different tasks. How can I achieve using redux-forms?
I tried using custom props, but that doesn't activate form validations.
Here is my code:
ParentContainer:
const props = {
onSubmit: this.confirmChangeBillingInformation,
}
return <CompanyDetails {...props} />;
Child component:
const CompanyDetails = (props) => {
<ChangePaymentInformation {...props} />
<ChangeCompanyPricing {...props} />
}
Grand child forms: There are two forms like this
const ChangeCompanyPricing = ({ classes, companyPricing, showChangePricingModal, actions, handleSubmit }) => {
return (
...
<form onSubmit={handleSubmit}>
<Button color="primary" type="submit" variant="raised">
Save
</Button>
...
)
}
In Parent Container change the name of the variable as handleSubmit because in child components you are getting handleSubmit props in ChangeCompanyPricing component.It is not at all defined.So change it.In the confirmChangeBillingInformation do the validation.I assume all the data required for validation will be available to the parent component
const props = {
handleSubmit: this.confirmChangeBillingInformation,
}
return <CompanyDetails {...props} />;
I developed a React App using Material-UI then I tried to create independent Components,
check the below independent components(<PanelDiv/>),
render() {
return (
<div className="panelDiv-component" style={{display:this.props.display}}>
<div className="panel-field-content">
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
/>
{/* <input defaultValue className="form-control"></input>*/}
</div>
</div>
);
}
I tried to use the component like this,
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
display={this.state.display[0]}
/>
But I can't update input field in this way.Also there is no error. How can i solve this? I want to update my input field.
Please check my input filed in the below image :
Because you are controlling the value of TextField by using value attribute but you are not updating the value by using onChange function, Since value of TextField is not changing so it becomes read only.
Solution:
Specify the onChange function with TextField and update the value inside that, Like this:
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
onChange={this.props._change}
/>
Inside parent component:
_Change(event, value){
//update the value here
}
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
_change={this._change}
display={this.state.display[0]}
/>
If you pass value as a prop to TextField you can't change that text!
On Material-UI official documentation they have used defaultValue="default val" as a prop.
So I used defaultValue as a prop! It worked fine for me!
<TextField
type="text"
defaultValue={this.props.val}
onChange={handleChange}
/>
Had the same error. I was not able to key in anything and it was because there was no name props included. example:
<TextField
type="email"
name='email'/>
Look at this example - https://jsfiddle.net/y857yeLq/
You should define a function, which is handles of text change and pass it to onChange property. In this example I used state for storing current text field value. I see, that you use props for that, but the principle is the same - function should update props in your case.
const { TextField, MuiThemeProvider, getMuiTheme } = MaterialUI;
class SliderExampleControlled extends React.Component {
state = {
value: '',
}
render() {
console.log(this.state);
return (
<div style={{width: '50%', margin: '0 auto'}}>
<TextField
hintText="Type here"
value={this.state.value}
onChange={(e) => this.setState(e.target.value)}
/>
</div>
);
}
}
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<SliderExampleControlled />
</MuiThemeProvider>
);
ReactDOM.render(
<App />,
document.getElementById('container')
);
I was running into this problem as well and I needed the onClick function to take more than just the event I also needed it to take the row number because my state had an array representing the rows in a table. I was able to do that using this chunk of code
onChange={(e) => this.nameChange(e.target.value, row.row_num)}
then in my function called nameChange I was able to update the value