Manage multiple redux form on page - reactjs

I have user data coming from back-end as an array of objects,
[{firstname: 'John', lastname: 'Doe'}, {firstname: 'Jane', lastname: 'Doe'}]
I am using a redux-form component to render these data.
tried to make the object keys dynamic by binding index to it, but then got unsure how to handle validation, data population etc.
Working code sample can be seen at,
https://codesandbox.io/s/determined-lake-ln25c
Now changing a field in on 1 form affects the other forms state. like after entering value in one field, all 'clear values' buttons get enabled.

The problem is that all your forms are actually assigned the same name (form property value) when you call reduxForm. This property is treated as unique form identifier so that data for specific form can be get from store. According to docs:
form: string [required]
the name of your form and the key to where your form's state will be
mounted under the redux-form reducer
Please note that although you generate unique formNumber using Math.random you're doing it only once in module file (please use console.log to see that formNumber is generated only once). So all instances of the UserForm component are assigned the same name at 'design time'. As a result when you then import form component and render it 3 times all instance use the same name. You can say that from redux-form point of view all these 3 form instances are actually the same single form and they use the same data from store.
According to redux-form docs all reduxForm config options
may be passed into reduxForm() at "design time" or passed in as props to your component at runtime.
So solution is to define unique form as a component prop at 'runtime' instead of in reduxForm config:
function App() {
return (
<div className="container">
<h1 className="mb-3">Users</h1>
<hr />
{userData.map((user, idx) => {
return <UserForm form={`form-${idx}`} key={`user_${idx}`} data={user} idx={idx} />;
})}
</div>
);
}
And of course remove this value from reduxForm config:
export default reduxForm({
validate
})(UserForm);
enter code here
This way all form instances are independent.
Since now all form instances are independent of each other you don't have to define field names this way:
name={`firstName_${idx}`}.
You can do it like this:
name='firstName'

Related

What is the best way for two-way binding a UI component to an observable to reduce rendering?

We are building an MVVM application using mobx and react. Currently our best bet is to create viewmodels and UI components similar to this simplified example.
// LoginModel.ts
export class LoginModel {
#observable
public userName: string;
#observable
public password: string;
}
// LoginView.tsx
#observer
export class LoginView extends React.Component<LoginViewProps> {
public render(): JSX.Element {
return (
<div>
<input type="text" value={this.model.userName} onChange={e => this.model.userName = e.value} />
<input type="password" value={this.model.password} onChange={e => this.model.password= e.value} />
</div>
);
}
}
AFAIK in this implementation the component will entirely re-render when either userName or password changes.
What I'd like to achieve is to have our own custom TextInput component which woudl be responsible for rendering the layout, styling, receiving user input, and also to show validation errors based on model state, etc. I see two options right now.
Expose the value, onChange and for example error in the custom component and use it similarly to the example above. This case the issue is the same, each change in a single observable property would AFAIK re-render the entire "form" component. This is due to the fact that I'm not dereferencing the observable in the TextInput component but in the LoginView.
Expose something like model: any and field: string and use model[field] inside. This way I would do the dereferencing inside the TextInput and it could work fine, BUT I'd loose some strong typing and universality.
A few notes:
At first run I intentionally wouldn't like to use libraries like react-forms, etc.
Also, if anyone spots it, I intentionally wouldn't like to use the Provider and #inject pattern, I like being explicit.
Could anyone give me some ideas and suggestions about such a scenario?
There is awesome form library for mobx that is using very similar technique https://formstate.github.io, you can probably copy this pattern from it.
You can use objects instead of plain strings.
interface Str{
value:string
}
then you can use .value inside your input component.

Redux Form - how to disable sync/async validation with a flag

I am looking for the most non invasive way to disable validation of redux form for dev/debug purposes
I have a wizard form similar to the tutorial https://redux-form.com/8.1.0/examples/wizard/ but I am using field validators plus an async validator
I would still like to display errors but be able to proceed to the next wizard step even when validation fails
I would like to add a flag to the url like ?ignore-validation=true (using react router)
here is a fragment of my wizard step1:
export class CustomerStep1 extends React.PureComponent<FormProps> {
render(): React.Node {
const {
handleSubmit,
} = this.props;
const submit = handleSubmit(createValidateCardAction);
return (
<form onSubmit={submit}>
<Field
name="card_number"
placeholder="7777 1234 5678 9012"
component={Input}
validate={cardNumber}
/>
...
export default reduxForm({
form: 'customerWizard',
destroyOnUnmount: false,
forceUnregisterOnUnmount: true,
})(CustomerStep1);
I see two possibilities here:
1) Split your wizard forms in more than one form and validate them separately. You could create another state to control which form you want to show. Even though it has more states to manage, I would pick that one.
2) You could leave just the async validation for each field and throw the errors there. Also, You must create a state to manage the page and manage it inside the async validation functions. I create an example of this second approach: https://codesandbox.io/s/o46k8lx7kz

How to store the information in react component.

When I am asking this question, lots of doubts are coming into my mind. well, first I will give my problem description.
I have component X. and it contains checkboxes and a search box.
while something typed (call it search_query) in search box,
X needed to update the checkboxes which matches the search_query. [note that I got all the values of checkboxes by some api call. and it is done when component created. ]
First doubts I came to my mind is that
store (search_query) and (values of checkboxes) in component state
if the values are more searching takes more time.
is it possible to change the values of props inside the component
or is there any other way to do it ??
Since no code is shared. Assuming you are using plain React ( no Redux, middlewares are used ).
Answering your question:
[1] Is it possible to change the values of props inside the component?
Changing props values inside the component is a bad approach.
"All React components must act like pure functions with respect to their props."
[ref: https://facebook.github.io/react/docs/components-and-props.html#props-are-read-only]
Also, the view doesn't get the update if props values changed within the component.
[2] or is there any other way to do it.
yes ( without mutation inside the component )
using "state" property to hold values & setState to update values.
[3] How to store the information in react component?
Let's rename component X as FilterData,
searchbox ( SearchBox ) & checkboxes (SelectionBox) are two individual components.
// Define state to FilterData
class FilterData extends React.Component {
constructor() {
super()
this.state = {
term: '',
searchResults: []
}
}
....
}
// pass the state values to child components as props
class FilterData extends React.Component {
....
render() {
return (
<div>
<SearchBox term={this.state.term} />
<SelectionBox options={this.state.searchResults} />
</div>
)
}
}
In React App,
data flows top down (unidirectional) and there should be a single source of truth.
SearchBox & SelectionBox are two individual (sibling) components,
SearchBox's state has terms ( which has the search string )
When the user enters input SearchBox will update its state and possible to detect change event and fire ajax and get the response.
How SelectionBox can detect search that had happened, how it can get data.
This is why the state is moved to common ancestor FilterData.
[Ref: https://facebook.github.io/react/docs/lifting-state-up.html]
[Ref: https://facebook.github.io/react/docs/state-and-lifecycle.html#the-data-flows-down]
Code Sample -----------------------------------------------------
Selected values are not saved:
https://codepen.io/sudhnk/pen/NgWgqe?editors=1010
Selected values are saved:
https://codepen.io/sudhnk/pen/JJjyZw?editors=1010

Redux form initialize only once though form names are different all the times

I am using redux form 5.3.2
My app needs user to submit N forms, ( value of N is decided at run time )
I receive only 1 form's fields, initial values & form Id from API.
As user submit 1st form, I send data to server and I get fields, initial values anf form id for second form.
I have a common form component to which I pass fields, initiaval values and form name all the times.
Code snippet is as below
In side parent component
<CommonForm
fields={myFields}
initialValues={fieldsInitialValues}
form={`form-${formId.toString()}`}
temp={fieldsInitialValues}
/>
Inside form component
class CommonForm extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
values: PropTypes.object,
temp: PropTypes.object
}
// other code and methods
render(){
// form rendering....
}
} // end of class
export default reduxForm({
// form: this value I am sending from parent component
destroyOnUnmount: false,
validate: formValidator,
overwriteOnInitialValuesChange: true
})(CommonForm);
I read about overwriteOnInitialValuesChange from http://redux-form.com/5.3.1/#/api/reduxForm?_k=f2zdrg
In redux store all forms are stored separetly under forms key
like form-1, form-2 etc
Problem is initial values are assigned only first time, next time I am getting undefined.
I dumped temp in side CommonForm, I am getting expected values like { field1: some value, field2: } some value
Where are things are going wrong?

Efficiently computing derived data from react props

We are in the process of implementing performance optimizations in our react/redux application. Part of those optimizations included introducing reselect. This worked nice for data that is derived directly from the state. but what about data that is derived from other props?
Example:
We have 3 components Feed FeedItem and Contact (Contact is a component for displaying a users contact information).
a FeedItem gets an object that represents an item in the feed, one of the properties of a feed item is an actor object. This object is like a user but a bit different (this sucks but can't be changed). This means that if I want to render a Contact for this actor I need to create a new object that maps the properties from an actor to a user. Creating a new object on every render is a performance anti pattern because we are using shallow equality checks.
e.g code:
<Contact
user={{
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
}}
</Contact>
Is there a pattern for solving this? reselect only supports derived data from redux state, this is basically derived data from props.
You can pass whatever you want to reselect's selector methods. It doesn't have to be state and props. That just happens to be it's most common use case. You can call one if it's generated selectors with any number of arguments.
Here's one way you could use it:
function convertActorToContactUser(actor) {
return {
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
};
}
class ActorContact extends Component {
constructor(...args) {
super(...args);
this.getUser = createSelector(
() => this.props.actor,
convertActorToContactUser
);
}
render() {
return <Contact user={this.getUser()} />
}
}

Resources