I am building form components - and I want to be able to give my own unique identifiers in the exports param. I also want to learn how to push validation schemas into these export sections. I need to get more control in this section otherwise all forms are thinking they are the "'syncValidationForm'"
import React from 'react';
import { reduxForm } from 'redux-form';
import validate from './validateForm';
import warn from './warnForm';
import FieldMaker from './FieldMaker';
import ButtonMaker from './ButtonMaker';
const FormShell = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<FieldMaker fields={props.fields} />
<ButtonMaker buttons={props.buttons} pristine={pristine} submitting={submitting} reset={reset} />
</form>
)
}
export default reduxForm({
form: 'syncValidationForm', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(FormShell)
You can create a factory function and export it:
function makeForm(id) {
return reduxForm({
form: id,
validate,
warn
})(FormShell)
}
export default makeForm;
And then you can create a form with custom id:
import makeForm from './FormShell';
const FormShell = makeForm('syncValidationForm');
// ...
Related
I have a simple modal in which I have a form on submit I display errors now I want to pass these errors to the children component.
Here is a simplified parent component
import React from 'react';
import Input from 'components/Functional/Input';
function Parent() {
const [errors, setErrors] = useState([]);
const handleSubmit = async e => {
const formData = new FormData();
}
return (
<Modal handleSubmit={handleSubmit}>
<Input setErrors={errors} ></Input>
</Modal>
)
}
export default Parent
Here is my children component
import React from 'react'
function Input({errors}) {
const [field, setField] =useState('');
console.log('errors', errors)
return (
<div>
<input type="text" onChange={e => setField(e.target.value)} />
</div>
)
}
export default Input
Now when I submit the data with errors, the console.log('errors', errors) in the children component I get undefined
What is wrong here?
Pay attention to props name. You're passing from parent a property called setErrors while in child component you're looking for errors. Try to rename property from setErrors to errors or simply read setErrors from <Input /> component
You seem to have a typo in your input component. You set the prop setErrors but your component expects errors. If you use plain javascript you should use proptypes to ensure this doesn't happen.
import React from 'react'
import PropTypes from 'prop-types'
function Input({errors}) {
const [field, setField] =useState('');
console.log('errors', errors)
return (
<div>
<input type="text" onChange={e => setField(e.target.value)} />
</div>
)
}
Input.propTypes = {
errors: PropTypes.arrayOf(PropTypes.string)
};
export default Input
See PropTypes
I've created a simple react component for a form with few input fields using formik. My form is rendered three times on my home page for three different type of users, but I only have one button that is outside the component and on click it should save the data inside the PersonalInformation component. This is how my code looks inside my App.js (ignore the users and data for now):
{users.map((data, i) => { return <PersonalInformation key={i} /> })}
<Button>Submit</Button> //this is the button that needs to save the data inside of PersonalInfo component od click
My question is how I can save the data inside the three forms on click on the button? In end-point on the back end I would like to get an array of three objects, each objects will contain info about each field in the form. I guess what I need is to pass data from PersonalInformation component to onClick()event in Button, but I am not sure how to do that with formik.
if you don't use any state management, context etc i think simplest way is you can pass reference to your save method upper.
import React, {useRef} from "react";
import PersonalInformation from "./PersonalInformation";
import "./styles.css";
export default function App() {
const saveRef = useRef(null)
return (
<div className="App">
<PersonalInformation passSave={(ref) => saveRef.current = ref}/>
<button onClick={() => saveRef.current()}> save </button>
</div>
);
}
//---------------------------------------------------------
import React, { useCallback, useEffect, useRef } from "react";
const PersonalInformation = ({passSave}) => {
const formInput = useRef(null);
const save = useCallback(() => {
console.log(formInput.current.value)
}, [formInput])
useEffect(()=>{
passSave(save)
}, [passSave, save])
return (
<input type="text" ref={formInput} />
)
}
export default PersonalInformation;
I am creating a redux-form shell with material ui inputs -- I am trying to create a genericForm handler that will allow a field and button object that could be pumped into the component -- I need now to create a form with no submit button due to design - but is able to submit the form on field changes if there are no buttons.
I have a handleChange function that will listen to onChange events for all field types - and bring back the fieldname and new value -- and it now has scope to know if the form hasButtons --- but I am unsure where and how to develop this further to submit the data to the parent if a field is changed
https://redux-form.com/6.0.0-alpha.7/examples/asyncvalidation/
FormShell.js
import React from 'react';
import { reduxForm } from 'redux-form';
import FieldMaker from './FieldMaker';
import ButtonMaker from './ButtonMaker';
const FormShell = props => {
const { handleSubmit, pristine, reset, previousPage, submitting } = props
return (
<form onSubmit={handleSubmit}>
<FieldMaker fields={props.fields} hasButtons={props.buttons.length > 0? true: false} />
<ButtonMaker buttons={props.buttons} pristine={pristine} submitting={submitting} reset={reset} previousPage={previousPage} />
</form>
)
}
export default reduxForm()(FormShell)
GenericForm.js
<FormShell
initialValues={this.props.initialValues}
enableReinitialize={true}//allow form to be reinitialized
fields={this.props.fields}
buttons={this.props.buttons}
form={this.state.uuid}// a unique identifier for this form
validate={this.validateHandler}// <--- validation function given to redux-form
warn={this.warnHandler}//<--- warning function given to redux-form
onSubmit={this.submit}
previousPage={this.props.previousPage}
destroyOnUnmount={this.props.destroyOnUnmount}// <------ preserve form data
forceUnregisterOnUnmount={this.props.forceUnregisterOnUnmount}// <------ unregister fields on unmount
/>
I turned this into a component and added a function that got the field changes from the FieldMaker component
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import FieldMaker from './FieldMaker';
import ButtonMaker from './ButtonMaker';
class FormShell extends Component {
constructor(props, context) {
super(props, context);
this.fieldChanged = this.fieldChanged.bind(this);
}
fieldChanged(field, value){
console.log("Fields have changed", field, value);
//if it doesn't have any submit buttons -- then submit the form on change of fields
if(!this.props.buttons.length > 0){
console.log("submit the form as a buttonless form");
setTimeout(() => {
this.props.handleSubmit();
}, 1);
}
}
render(){
const { handleSubmit, pristine, reset, previousPage, submitting } = this.props
console.log("THIS FORM SHELL PROPS", this.props);
return (
<form onSubmit={handleSubmit}>
<FieldMaker fields={this.props.fields} fieldChanged={this.fieldChanged} />
<ButtonMaker buttons={this.props.buttons} pristine={pristine} submitting={submitting} reset={reset} previousPage={previousPage} />
</form>
)
}
}
export default reduxForm()(FormShell)
I have a React/TypeScript Component that I'm trying to import mock data into and then iterate over it to display a specific attribute in a span element.
The issues I'm running into are that I can't seem to pass the mock data into my component to iterate over it and at the same time I'm also getting weird type errors that seem to suggest that I'm either using the type definitions of my data or the data itself for my props but never both.
I created a CodeSandbox to highlight these issues and I included my main component where I'm seeing the errors below:
Current Component
import React from 'react';
import contacts from '../../mock-data/contacts-mock-data';
import { Contacts, ContactGroup } from '../../services/contacts-client';
type Props = {
contacts: Contacts[];
contactGroups: ContactGroup[];
};
export const ContactGroupsSection = (props: Props) => {
const { contacts, contactGroups } = props
let groups = () => {
for (let i = 0; i < contacts.contactGroups.length; i++) {
return <span>{contacts.contactGroups.contactGroup}</span>;
}
};
return (
<div>{groups}</div>
);
};
I tweaked your codesandbox to pass the data into your component as you suggested.
App.js
import React from "react";
import "./styles.css";
import { ContactGroupsSection } from "./contact-groups";
import contacts from "./contacts-mock-data";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<ContactGroupsSection contacts={contacts} />
</div>
);
}
contact-groups.tsx
import React from "react";
import { Contacts } from "./contact-types";
type Props = {
contacts: Contacts;
};
export const ContactGroupsSection = ({ contacts }) => {
const groups = contacts.contactGroups.map(contactGroup => (
<span>{contactGroup.contactGroup}</span>
));
return <div>{groups}</div>;
};
Hope that helps!
My purpose is to create a register form which consist of two step. For the first step, user input their credential and then I want to async validate if username is already existed against backend. If everything is alright, then he/she can click next to continue to another step but all the data is not yet submit to server at this point. The second step, user need to fill some of there information and click submit in order to complete the registration and send data to server. To achieve this, i consider create two components. The first component is responsible for user credential and another component is responsible for user detail. After these two components are created, then i will create another class which will import these two components. The third class is created to make sure that all properties is safe if user click back from second step to the first step (I am not sure if this is the right way but it is what i can think of based on my current knowledge in programming language. Please suggest me if there is a better way.).
To valid client side, I choose to use withFormik and Yup. But, the problem is that, i could not make it work and valid my client side. It always throw me lot of error by return FormikApp in render method. I have tried return App but it doesn't work too.
import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from "react-router-dom";
import {
Row,
InputGroup,
Col,
Navbar,
Nav,
NavDropdown,
Form,
FormControl,
Button
} from "react-bootstrap";
import { Form as FormikForm, Field, withFormik } from "formik";
import * as Yup from "yup";
import axios from "axios";
class UserCredential extends React.Component {
App = ({ values, errors, touched }) => (
<FormikForm className="register-form " action="">
<h3 className="register-title">Register</h3>
<Form.Group className="register-form-group">
<Field
name="username"
type="text"
placeholder="USERNAME"
className="form-control rounded register-form-control" />
{touched.username && errors.username && <p>{errors.username}</p>}
</Form.Group>
</FormikForm>
);
FormikApp = withFormik({
mapPropsToValues({ username }) {
return {
username: username || ""
};
},
validationSchema: Yup.object().shape({
username: Yup.string()
.min(6)
.max(32)
.required()
.test("username", "error message of username", async value => {
return true;
})
}),
handleSubmit(values) {
console.log(values);
}
})(App);
render() {
return (
{this.FormikApp}
)
}
}