redux-forms initialization not working after upgrade to 7.x - reactjs

I have upgraded my recct-redux application to user redux-form 7.x (latest at this time). After update, initial values aren't getting populated in the form. (It used to work with redux-forms 2.x)
Is it a bug or am i doing something silly ?
Below is my code link
https://github.com/santhoshml/Bookbild-UI/blob/master/src/components/user_profile.js
[Update] : I found the problem (but I still don't have an answer) ,
I made 3 calls to the backend server and each one returned at it own time and each kept overwriting the other. If I keep refreshing, the values keep doing disco :)
Now I have wrapped all the 3 calls in Promise.all and I can see all the fields populated, BUT when I edit and submit, onClickHandler doesn't have any updated values.
To debug this, I printed the props in the render and it does not have the values returned from db. But surprisingly the values are populated in the textfields. This is amazingly confusing. Please help. Link below
https://github.com/santhoshml/Bookbild-UI/blob/master/src/components/user_profile.js
Thank you in advance,
Santhosh mL

Did you check this documentation out. According to that you will need to connect() to the Redux state yourself and map from the data reducer to the initialValues prop. So it should be something like this.
// Decorate with reduxForm(). It will read the initialValues prop provided by connect()
InitializeFromStateForm = reduxForm({
form: 'initializeFromState' // a unique identifier for this form
})(InitializeFromStateForm)
// You have to connect() to any reducers that you wish to connect to yourself
InitializeFromStateForm = connect(
state => ({
initialValues: state.account.data // pull initial values from account reducer
}),
{ load: loadAccount } // bind account loading action creator
)(InitializeFromStateForm)
export default InitializeFromStateForm
What you need to do is provide the action to load the data. Then map over the data and set it into the initialValues property.

Related

How to not lose my information in props when i reaload my pages?

I'm new in react and i'm studing a method to make connections with Firebase to my Project.
With props I can pass an ID and search it in firebase, but when i reload my page, all the props are lost and i have this message in the image:
The value is Undefined because the props are losing their values
Is there any other way for this information don't lost?
I dont try anything because idk what to do.
The ID in the props will be used in useEffect() on my page.
Edit:
There is the Cards Image:
Cards
And here it's when i click on the card "Pinscher":
The page when i click on Pinscher
But when i Reload the page "Pinscher", i lost the Id passed with props.
The most straightforward way I know to persist data over a reload is to save it to localstorage or sessionstorage. Which one to use--and whether it's appropriate--depend on your actual use case, which we can't comment on without more knowledge of your project.
Assuming you did want to use that, a basic implementation would be to write helper functions when you set state to also save the data to storage. Your initial state load would then look for storage information as its default and then fallback to null if it can't find anything in storage.
const [arbData, setArbData] = useState(window.localStorage.getItem('arbData'));
const setArbDataWrapper = (data) => {
setArbData(data);
window.localStorage.set('arbData', data);
}

Reset form to empty values

new to redux-form... I was looking at an example from redux-form docs where one can initialize form values from initialValues (forked example here: https://codesandbox.io/s/6v3n9lwnpr).
Is it possible to have functionality where one can use 'Undo Changes' to reset form to InitialValues, but also have another button to reset to empty form?
If you go to the redux-form documentation, you will find what you need under the action creator section. With that, let's answer your questions.
one can use 'Undo Changes' to reset form to InitialValues
In its documentation, Redux-Form lists out a couple of actions that you can use. You can either use an action creator or used an action that is already bound to the dispatch. For your requirement, you'll need to use the library's reset function
a) using action creator
import { reset } from 'redux-form';
...// then inside a function you can dispatch the reset action.
resetMyForm() {
const action = reset('myFormName');
dispatch(action);
}
b) using an action already bound to the dispatch
I wont type this since there is an example in the library on GitHub here
And as for
button to reset to empty form
similar to the initial answer but you would have to use the clearFields function instead.
Hope this helps.

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

Where should I load data from server in Redux + ReactJS?

For example I have two components - ListOfGroupsPage and GroupPage.
In ListOfGroupsPage I load list of groups from the server and store it to the state.groups
In route I have mapping like ‘group/:id’ for GroupPage
When this address is loaded, the app shows GroupPage, and here I get the data for group from state.groups (try to find group in state via id).
All works fine.
But if I reload page, I'm still on page /group/2, so GroupPage is shown. But state is empty, so the app can't find the group.
What is the proper way to load data in React + Redux? I can see this ways:
1) Load all data in root component. It will be very big overhead from traffic side
2) Don't rely on store, try to load required data on each component. It's more safe way. But I don't think that load the same data for each component - it's cool idea. Then we don't need the state - because each component will fetch the data from server
3) ??? Probably add some kind of checking in each component - first try to find required data in store. If can't - load from the server. But it requires much of logic in each component.
So, is there the best solution to fetch data from server in case of usage Redux + ReactJS?
One approach to this is to use redux-thunk to check if the data exist in the redux store and if not, send a server request to load the missing info.
Your GroupPage component will look something like
class GroupPage extends Component {
componentWillMount() {
const groupId = this.props.params.groupId
this.props.loadGroupPage(groupId);
}
...
}
And in your action...
const loadGroupPage = (groupId) => (dispatch, getState) => {
// check if data is in redux store
// assuming your state.groups is object with ids as property
const {
groups: {
[groupId]: groupPageData = false
}
} = getState();
if (!groupPageData) {
//fetch data from the server
dispatch(...)
}
}
I recommend caching the information on the client using localstorage. Persist your Redux state, or important parts of it, to localstorage on state change, and check for existing records in localstorage on load. Since the data would be on the client, it would be simple and quick to retrieve.
The way I approach this is to fetch from the server straight after the store has been created. I do this by dispatching actions. I also use thunks to set isFetching = true upon a *_REQUEST and set that back to false after a *_SUCCESS or *_FAILURE. This allows me to display the user things like a progress bar or spinner. I think you're probably overestimating the 'traffic' issue because it will be executed asynchronosly as long as you structure your components in a way that won't break if that particular part of the store is empty.
The issue you're seeing of "can't get groups of undefined" (you mentioned in a comment) is probably because you've got an object and are doing .groups on it. That object is most likely empty because it hasn't been populated. There are couple of things to consider here:
Using ternary operators in your components to check that someObject.groups isn't null; or
Detailing in the initialState for someObject.groups to be an empty array. That way if you were to do .map it would not error.
Use selectors to retrieve the list of groups and if someObject.groups is null return an empty array.
You can see an example of how I did this in a small test app. Have a look at specifically:
/src/index.js for the initial dispatch
/src/redux/modules/characters.js for the use of thunks
/src/redux/selectors/characters.js for the population of the comics, series, etc. which are used in the CharacterDetails component

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