I have a form, which is populated using various types of question fields (e.g. text input, email, number, radio box, tags, custom inputs ). These field types are fetched dynamically based on prior choices of user on a previous form.
Now, I have to validate the different form fields when user submits the form using React. The issue is that I can't simply check the value attribute of the fields, since some fields are complex and we get the value after applying some calculation, replacing-non-numbers, or some fields may have radio buttons and corresponding text inputs etc. How can I go about this validation in React? My general structure is this:
<form>
{ this.props.questions.map((question, index) => {
return <Question key={index} data={question} validationError={this.state.validationErrors[question.name]} />
})}
</form>
<button onClick={this.validateFields}>Submit</button>
Is it possible to loop through components in validateFields method of this component class? Or I need to loop through the html nodes that are rendered in the final HTML?
Earlier I was doing this using jQuery and was looping through the question div elements and applying custom validation rules depending on the question type (stored in a data attribute).
Now, I am not sure what is the correct way to do this in React.
You're applying jQuery (and vanilla JS) patterns of thinking to React. I suggest to stop considering you have DOM in any form. No DOM, no components list either, do not touch it or React will be a pain instead of help.
All the data you want to have must be in state. That's the purpose of this library.
So, in your case it is better to go this way:
1) Implement onChange event in Question and other field components. Regardless of how complex they are, your could stream their data into a signle argument, aren't you?
2) Add onChange handler in your form with something like
onChange={value =>
this.setState({
fieldValues: {
[index]: value
}
})
}
3) Populate fieldValues like this:
constructor(props) {
super(props);
this.state = {
fieldValues: props.questions,
};
}
And voila - all the form data are already in this.state.fieldValues, ready for any ongoing usage.
Surprised? So I was, when I first been understanding user input in React. Check this section in React docs for the source of the idea: https://reactjs.org/docs/forms.html#controlled-components
Related
this is my first question here,pardon me for any mistake. So ,I have a few inputs and for displaying the values of them I used some elements like h1 and div's which are in a seperate component. I want my elements to have some default value, so for that I kept them in state and then I call an onChange function on inputs which will update my elements state. I tried doing it with event.target like nameElement:event.target.value ,it would have worked if i had one input but because I have multiple inputs ,when I change an input field it gets overwritten by the one I change next. So how can I update only the input field I change. Like if I write something in name input field only the element of CV which is holding the name field should change . Here's my code sandbox link https://codesandbox.io/s/cool-glitter-9w2mh?file=/src/App.js
I am not sure, I got the issue right. But I got into the sandbox and below are my observations.
I would advise using Formik if you are dealing with the user-input form. Link - https://formik.org/docs/tutorial
Since you have created a single state that contains default value as well as user input value, any changes made by the user is not saved after clicking on "viewCV" link that re-renders entire component.
Changes Required
Have two states : initialData and userDetails.
Modify handleChange
handleChange = (input, e) => {
this.setState((prevState) => {
return {
...prevState,
[input]: e.target.value
};
});
};
In components such as workExp, education make sure you link handleChange as an arrow function for the "onChange" event.
<input onChange={(e) => handleChange("job", e)}>Email
Modify submit button to render the Resume template with user inputted values.
Modify viewCV link which is causing entire parent component re-rendering.
So I have a form inside a master page, where it will render different textbox, or radio box, or date picker, etc. On every click of next button and back button, it will either go to the next component or prev component, and save the whole form.
Pretend data model will look like this
{field: [{textbox1: texbox1value}, {datepicker1: datepicker1value}]
Given a pseudocode more or less like this.
ContainerPage.ts
<form>
renderComponent(listOfComponent) // this will switch based on the link
<button back>
<button next>
</form>
Component1.ts
<input textbox>
Component2.ts
<input datepicker>
I was able to get it going to save, but wondering how do you validate the input if the button is on the parent component?
I'm following this site more or less but it does not have validation
https://css-tricks.com/the-magic-of-react-based-multi-step-forms/
I also saw some site develop it in such a way the form is on each component instead of the master page. but ended up using 1 form.
Theres are some ways to handle that. My favorite way is to add a callback function to the form-component that will be called when the validation of the form is changed.
So you never need to check the validation of the form from outside of the component and everywhere you need that form you got the validation state.
Look at that example
https://codesandbox.io/s/charming-glitter-10db0
here we has two components App and Form
Form: Here we handle all the fields and validations
App: Here we got the callback of the validation state and we are able to print a error message or disable the buttons
I'm trying to integrate react-day-picker's DayPicker with react-final-form.
React Final Form requires the use of a Field for each form field, which means creating an adapter component whenever you want to a third-party form element to be usable within the form. The adapter component has to accept an input object containing value and onChange. The advice is just to provide a new onChange.
This approach, which works for many other components, doesn't work for DayPicker. It seems like the issue is that DayPicker doesn't actually have an onChange method, so it's up to us to manage what happens when the calendar changes and then store the dates in value property that react-final-form expects.
I've created a codepen here: https://codesandbox.io/s/github/pcraig3/date-picker-sandbox
I have a handleDayClick method in Calendar.js which runs when days are clicked, but onChange isn't being triggered for the calendar consistently.
selectedDays is being updated immediately within the Calendar itself, but the Form is not getting the correct dates until the calendar is unfocused
The form's validate method is only being called once (the first time selecting a day), whereas it is called each time the native text input value is updated.
I would like the form values to be synced up with the calendar's external state and for the validate method to be triggered each time a day is clicked/unclicked. Is this possible to achieve or am I doing completely the wrong thing?
It's probably easier to use the <DayPickerInput> component, instead. That component uses a standard HTML input, which supports onChange. I did it like this:
<Field name={id}>
{({ input, meta }) => (
<React.Fragment>
<label htmlFor={id}>Date: </label>
<DayPickerInput
{...input}
onDayChange={day => input.onChange(day)}
inputProps={{ id: id }}
/>
{meta.error && meta.touched && <div className="error">{meta.error}</div>}
</React.Fragment>
)}
</Field>
According to the documentation, you can add the logic to the "inputProps" prop, since this takes in props to the input component, you can also add css to it as well.
inputProps Object
: Additional props to add to the input component.
Your code will look like this:
const dateChanged = day => (console.log(day)); //function to call when date changes
inputProps={{
style: styles.dayPickerInput,
onChange: event => dateChanged(event.target.value),
}}
If you use onDayChange alone, it'll fire after the user "clicks" to select a day, not when the user actually types a date inside the input field, using this extra onchange listener will be a safeguard for you, if the input field is enabled for users to type in the date, which they might.
I have a form with some input fields (some of them hidden until a checkbox is checked. When I check/uncheck the checkbox a specific state is set (this.state.isChecked = true/false).
On render method, i have a div (containing some input fields) with some classes and this condition for "show" class: <div className={'extra-fields ' + (this.state.isChecked? ' show' : '')}>...</div>
Expected behavior is that on state change, only the "show" class is putted or deleted from div
Current behavior: the entire form is rendered again and all data written in the input fields are lost.
How it should be done this?
If the value of the input fields is important (which they apparently are), and if they can change (which the obviously can), then React should be aware of them, typically in state.
The 'standard' (on only) react way to maintain the contents of the input fields is:
put the content of the input fields in state as well,
include something like value={this.state.foo} and onChange={this._onChange()} to the render of each input field
include the _onChange() function to the form to handle input changes
That way, whenever the form is re-rendered (after each setState()), the input values are also preserved.
PS: The question title "stop reactjs component from rerender on state change" does not really cover the question from text: you are asking for a partial re-render: do re-render the show/hide extra fields based on checkbox, but do not re-render input fields.
The short answer is that you can prevent a component from rendering/updating with the shouldUpdateComponent life-cycle event: https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate
However, I agree with the previous answer, that for the sake of doing what sounds like a partial re-render, and to follow best practices in general, you should be storing the state of your input fields somewhere in a component so that they persist beyond a render call.
I have created a list of input tags wrapped in a div to produce an editable text list.
However, when I add a new element to this list by hitting Enter, the new empty element is automatically populated with the last keyboard input, instead of being blank.
Here is a link the JsBin describing the issue:
https://jsbin.com/kovipurace/edit?html,output
I am expecting an empty input instead.
Is there a way to implement the expected behaviour correctly?
I initially based my code off of the CommentForm in the react tutorial, but I have deliberately not used a form tag to give cleaner use of the hitting the Enter key (don't want to mess around with e.preventDefault() etc.) I have also put in additional functionality in the actual version to allow updating existing values using an onBlur event.
What I have tried:
I have (correctly, hopefully!) implemented controlled components as stated in the docs.
I have experimented with using defaultValue and instead of value but the effect is the same. In both cases I am using {this.props.value}
You create new textentries with textEntry text.
keyHasBeenPressed : function(e) {
if (e.keyCode == 13) {
var textEntry = this.refs.textEntry.value;
this.props.createEntry(textEntry);
}
},
All you need is to make the args of createEntry blank.
this.props.createEntry();
https://jsbin.com/daqura/1/edit?html,output
I found help on #reactjs IRC channel and commenters here.
In the keyHasBeenPressed function, the state needs to be set explicitly again, as it is in handleChange.
getInitialState is just used to intialize state once in a component's life cycle.