Unique name for redux form - reactjs

So I'm trying to make generalised Form component that I export:
export default reduxForm({
form: 'form name', // I'd like to set this based on this.props.name
validate // & this.props.validate (but obviously props isn't accessible)
})(Form)
but obviously the export statement is outside the class component, so it doesn't have access to the name/validate props of this specific Form.
Is it possible to do? Or have I misunderstood how I should be structuring this?

This is an interesting question.
Based on reduxForm architect, of course it tries to setup a string, for instance, unique identifier, so that if you have multiple form, the values can be arranged in the right objects.
If you want to attach another string, then you are looking at the run-time variable of a form, which is exactly a field :)
Give you an example, form1.values["name"] = "Form1". Btw I might not give you the right syntax, since I'm not familiar with reduxForm, but the idea is similar.

Related

Creating a meal planner in React (MERN), wanting to reuse a component for adding and editing meals

I’m creating a meal planner and I want to use the same modal component to add and edit meals, because they are exactly the same. The modal includes inputs for name, ingredients and the day of the week to make it. When adding new meals, I want the modal inputs to be empty and when editing I want the inputs to have the current data so the user doesn’t have to re-enter all of it.
My attempt so far has been to enter a prop string to the PlannerModal that is either “add” or “edit” and either do a fetch post or put depending on that prop. This seems to work ok, but I’m running into the problem of setting the data into the inputs with the value attribute which I do not want when adding a meal, so I’m thinking there has to be a better way of organizing all of this, aside from creating two different modals.
My component hierarchy looks like this if it helps:
I don't see a problem with your approach, However, there are a few improvements I can come up with, first, instead of passing “add” or “edit” as string, you should try using enum in this scenario, and I assume the issue you are having is caused by having the value property, if that's the case, you can do something like
const inputProps =
props.mode === Mode.Edit
? {onChange: ...., value: something}
: {value: something, disabled: true}
and then you should be able to spread the inputProps into your input element like
<input {...inputProps} />
sounds a bit confusing but just giving you an idea to pas props optionally

Formik - Update initial values after API call

I'm getting my inputs dynamically from an API call based on a change in select input, but when I try to add to the initial values of Formik, it always gives me an error ...
Warning: A component is changing an uncontrolled input of type text to be controlled.
And it doesn't help if I set enableReinitialize={true} to Formik.
However, if I generated the inputs from a local JSON or object, the error goes away.
What am I doing wrong here ...
https://codesandbox.io/s/test-dynamic-inputs-with-formik-xr9qg
The form submits fine though.
Better use enableReinitialize={true}. This is official Formik API.
You can check this issue
If anyone is facing the same issue, I just found the solution ...
You have to set value={field.value || ''} in the input inside the TextInput component or whatever type you're using in order to fix this issue.
I had a complex, dynamic form and also came across this issue. There are a few things that I'd recommend for anyone debugging this issue in the future:
Set value for your Field component--like Ruby does above.
Ensure that your Formik component has a uniquely identifying key.
Track and debug your initialValues and ensure that all fields are accounted for. You shouldn't have to set the field value like Ruby does--so long as your initialValues object accounts for all of the fields. However, my form dynamically changed Field components--and Ruby's solution is the only one that worked.
If your form is not dynamic--I think it might be best to check your initialValues object first before implementing Ruby's solution. Formik should be taking care of those values for you--which is why it's such an awesome tool.
i've checked with enableReinitialize={true}. But its not working as much as expected. so wrote a useEffect like
useEffect(() => {
formik.setFieldValue('query_string', active?.query);
}, [active])
it's worked !

Import default react component with two or more different name

What I am trying to do:
Import the same default component twice or more times in one file. The reason of why I want to do this are because the component are the same, I only need the name difference to make it more readable.
What I have done:
import ToInput from './input';
import FromInput from './input';
Is there a correct way to do this? It works, but the ESLint is complaining about duplicate import.
import Input as MyInput from './input';
import Input as MySecondInput from './input';
Now you may use the component as MyInput or MySecondInput, as both are references or instances of the same component.
You shouldn't ever need to do this. Post the scenario as to why you need this.
Just do this:
const FromInput = ToInput;
Or just disable the eslint rule for that file if you really need it.
/* eslint-disable import/your-rule-here */
It seems like what you really want to do is create two distinct instances of an Input component, but what you have described is to create a copy of the Input component class/descriptor. While it is possible to do this, it is usually a bad practice.
Try to think about React in terms of Object Oriented concepts. Remember that the imported construct from './input' (in your case, ToInput) is a Class and not yet an Instance of that class.
Traditionally to create an instance of a class called Input, we would write something like this:
var toInput = new Input()
However, when defining an instance of the class Input in React, we typically use JSX tags:
<Input />
The above is JSX tag is an instance of Input, and NOT actually the Input class itself.
From what I gather in your question, I think the following would be a more appropriate approach that employs better patterns and practices.
Import a singular, generic Input component descriptor/class.
import Input from './input'
If readability is your ultimate goal, then perhaps differentiate the two components with a prop, rather than creating copies of the component class. You could use an id prop for example:
<Input id='to-input' />
<Input id='from-input' />
Hopefully this answers your question.

react-form: How to use multiple forms in combineReducers?

Disclaimer: It is possible, that this question seems stupid because I might have overlooked anything obvious or self-evident in the docs. For now my reducer-setup looks like this:
import editBlogEntryForm from './blog/editBlogEntryForm';
import login from './login'; // <-- a directory with index.js
import blog from './blog'; // <-- a directory with index.js
export default combineReducers({
blog: blog,
login: login,
form: editBlogEntryForm
});
Where shall I put other forms in the future?
Learning more about seperating reducers, I moved the blog and login reducers into their own directories/files where I use reducer composition. But it seems I cannot move the form anywhere, it has to stay top-level, which does not make sense, if I later want to introduce a login-form or so. I hope I don't have to put everything into the same form-reducer, resulting in a quite big switch-statement?
I already tried moving the form: editBlogEntryForm "down" into the blog reducer, but the form stops working/updating then.
Here is the reduxForm call in my container-component for the form:
EditBlogEntryFormContainer = reduxForm({
form: 'EditBlogEntryForm',
validate
})(EditBlogEntryFormContainer);
Can someone please point me the right direction please?
From the redux-form-docs http://redux-form.com/6.6.3/docs/GettingStarted.md/ I got this:
Note that, by default, the key used to pass the redux-form reducer to
combineReducers should be named form. Although there is support for
custom key names, see getFormState config for more details.
Thanks to #Thijs Steel and his pointing me to the getFormState prop of reduxForm() (see docs http://redux-form.com/6.6.3/docs/api/ReduxForm.md/), I came to a solution that is working with verbose form name and state-location. Though I still cannot follow the docs saying about getFormState:
This functionality is rarely needed, and defaults to assuming that the
reducer is mounted under the form key.
I think we all want more than one form and form-reducer in our apps, so using getFormState rather seems the standard case to me. But still, I'm not sure, I might have missed anything obvious.
Solution is to change the connection of the form-component with the redux-form like this:
EditBlogEntryFormContainer = reduxForm({
form: 'EditBlogEntryForm',
getFormState: (state) => state.blog.editBlogEntryForm, // <-- your form reducer location
validate
})(EditBlogEntryFormContainer);
So any form can have its state from any location of the app's state making multiple forms possible.
Not using getFormState is defaulting to using the form-reducer from top-level of the state, which would result into this:
EditBlogEntryFormContainer = reduxForm({
form: 'EditBlogEntryForm',
getFormState: (state) => state.form, // <-- default of reduxForm
validate
})(EditBlogEntryFormContainer);
First of all, if you want to add another form in the Future you could call it form2: ... (Or some other, more apropriate name).
When you moved the form down, did you also use combinereducers to combine the lower level ones?. If so, bear in mind that to acces the state you would need to do state.blog.form and state.blog.main

Relationship between list and item with relational data store (using react-redux)

I'm using React with Redux as my store. I'm also using the react-redux library to integrate the two. My store contains two sets of data:
Task { id, name, assigneeId }
User { id, name }
I have a TaskListComponent which (using react-redux) connect-s to my store using:
#connect(state => {
tasks: state.tasks,
users: state.users
})
I need both because the list has a filter allowing for searching my task name or user name - my component needs to be 'user aware'.
This component lists out another component called TaskItemComponent which displays the task name and the name of the assigned user.
I'm struggling to decide on the best approach for resolving a task's assigned user.
React guidelines tell me that the Item component should take a Task as a prop, and resolve the User itself in the render function. However, this requires the component to be store-aware and, using the react-redux library, it doesn't appear to be designed to allow a component to access the store without being connect-ed to it.
Or I could resolve the User in the list and pass it to the Item component along with the task, e.g. <TaskItemComponent task={task} assignee={resolveTaskAssignee(task)} />. This has the benefit of keeping my Item 'dumb', and means I don't need to have it listening to store changes (or even know about the store).
Any advice would be appreciated.
Both approaches are fine. I'd start with passing props from outside, and once it gets tedious, let the Task component receive task as a prop but read its user by using connect.
See also https://stackoverflow.com/a/25701169/458193.
There's nothing inherently wrong with option #2. You have to do data ops somewhere. It will always be the right place to do those ops in the smart component.
Personally, I'd prefer a better data model in the store. But, you got what you got.

Resources