Form not updating when connected value is updated (Redux Form) - reactjs

I am building a form using React and Redux Form. I use the formValueSelector to connect to several input fields. However, when I update these input fields in the UI, the form is not re-rendered. My code looks like this:
// HelpForm.jsx
import React from 'react';
import { connect } from 'react-redux';
import { reduxForm, formValueSelector } from 'redux-form';
import CategorySelectBlock from 'apps/help_form/components/CategorySelectBlock';
const selector = formValueSelector('help_form');
const mapStateToProps = state => ({
category: selector(state, 'category'),
subcategory: selector(state, 'subcategory')
});
class HelpForm extends React.Component {
render() {
const {
category,
subcategory
} = this.props;
console.log('Rendering HelpForm');
console.log('category:', category);
console.log('subcategory:', subcategory);
return (
<form id="helpform">
<CategorySelectBlock
category={category}
subcategory={subcategory}
/>
</form>
);
}
}
const ReduxHelpForm = reduxForm({
form: 'help_form'
})(HelpForm);
export default connect(
mapStateToProps
)(ReduxHelpForm);
I can see from my console logs that this HelpForm component is only rendering once, even after I select a new value for the category or subcategory fields (these are defined within the CategorySelectBlock component).
Am I doing something wrong, or misunderstanding how formValueSelector works? Any guidance would be much appreciated. Thank you!

I figured it out. I wasn't passing the onChange property through my custom input type.

Related

Redux-Form initialValues not working with redux-form/immutable

The problem
https://codesandbox.io/s/3o4j9y375
What I have
Ok, this one is really tricky... I have the following code :
Form = connect((state, props) => ({
formValues: getFormValues('myForm')(state),
initialValues: props.values,
}))(Form);
What I expect
Having in my Form props both formValues and initialValues.
Where did it go wrong?
First I just wanted formValues to be in my Form props : I encountered an issue with that because i am using IMMUTABLE so I had to import like this
import { getFormValues } from 'redux-form/immutable';
Instead of like this
import { getFormValues } from 'redux-form';
Once that fixed I wanted to add some initialValues to my form as showed above and THAT is is the problem.
I console logged my props in Form and initialValues are passed but not in the JSON format that I used but in an IMMUTABLE MAP...
But in this format, the values are not injected in the form.
TL/DR
import redux-form/immutable -> can use getFormValues but initialValues are stored as immutable Map so not working
import redux-form -> cannot use getFormValues but initialValues are stored in JSON so it's working
You can use formValueSelector https://redux-form.com/7.4.2/docs/api/formvalueselector.md/
import { formValueSelector } from 'redux-form/immutable'
const selector = formValueSelector('myForm');
const mapStateToProps = (state) {
formValues: selector('myForm')(state),
}
export default connect(mapStateToProps)(Form);

Redux-form ownProperties is undefined

I have a redux-form that I'm connecting to the state as follows:
export default connect(mapStateToProps)(reduxForm({
form: 'MyForm',
validate // validation function given to redux-form
})(MyForm));
I now would like to get a slug value which is a react-router param (after navigating to the page like this:
browserHistory.push(`/mypage/${slug}`) ). However ownProps is empty:
const mapStateToProps = (state, ownProps) => {
console.dir(ownProps); // ISSUE: this is empty
const someField = selector(state, 'someField');
...
};
I tried different ways of connected to redux-form, but haven't been successful. Would really appreciate any hints on how to solve this.
I think I have understood your problem here. You need to connect the redux form in order to get values using selector. Please see example code below. Hope it will help you.
import React from 'react'
import { Field, reduxForm, formValueSelector } from 'redux-form'
import validate from './validate'
import example from './components/example'
import { connect } from 'react-redux'
function myForm ({
someProp,
exampleClick
}) {
function handleSubmit (e) {
}
return <form onSubmit={handleSubmit}>
<Field
name='name'
component={example}
submitBtnClicked={exampleClick} />
</form>
}
let thisForm = reduxForm({
form: 'myForm',
validate
})(myForm)
const selector = formValueSelector('myForm')
thisForm = connect(
state => {
const someField = selector(state, 'someField')
return ({someField})
}
)(thisForm)
export default thisForm
I solved it by adding react-router's withRouter around my connected component:
export default withRouter(connect(mapStateToProps)(reduxForm({
form: 'MyForm',
validate // validation function given to redux-form
})(MyForm)));

Redux-Form Initial values

So I'm trying to load a Redux Form pre populated with values from my store. However I'm unable to get anything back other than null. Been at this for several hours now and been reading over several SO examples trying different things and think I'm just at a wall on this.
Following this Redux Form Initializing from State example
Redux: 3.6.0
React-Redux: 5.0.3
Redux-Form: 6.6.3
React: 15.4.2
There is a parent component that is rendering a child component which is the form. For sake of brevity going to put in the bare minimum of code and make names as generic as possible. Everything loads fine but I think the issue relies in not properly connecting to my store. Or rather I should just be loading the data on a componentWillMount?
Parent Component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUser } from '../actions/usersActions';
import ChildForm from './ChildForm.jsx'
#connect((store) => {
return{
user: store.users.user
}
})
export default class Parent extends Component{
componentWillMount(){
this.props.dispatch(fetchUser(this.props.match.params.id))
}
submit = (values) => {//do some stuff}
render(){
return(
<ChildForm onSubmit={this.submit} />
);
}
}
ChildForm:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { user } from './reducers/usersReducer.js';
class ChildForm extends Component{
render(){
console.log('FORM STATE >>>>>>>>>>', this.state); //Returns NULL
const { handleSubmit } = this.props;
return(
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="first_name" component="input" type="text"/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}
ChildForm = reduxForm({
form: 'childForm',
enableReinitialize : true // I found this in another SO Example
})(ChildForm);
ChildForm = connect(
state => ({
user: state.user,
initialValues: state.user
}),
{ fetchUser }
)(ChildForm)
export default ChildForm;
enableReinitialize SO
usersReducer.js
export default function reducer(state={
user: {},
}, action){
switch (action.type){
case "FETCH_USER_FULFILLED":{
return{
...state,
user: action.payload
}
}
}
return state;
}
So this is where I'm at currently. Can get the page, form, and submit all work. However I can't seem to figure out how to get my Store values out and into the form fields. Any help would be greatly appreciated.
Looks like everything is wired up correctly but I wasn't pulling in the correct object in the store.
ChildForm = connect(
state => ({
initialValues: state.users.user
}),
{ fetchUser }
)(ChildForm)
...Always something little

Access a Field value with Redux-form - dependent Fields

I have a decorated component with redux-form HOC and I want to access a Field value from the decorated component to enable/disable and hide/show other fields. what's the best approach to do that?
I tried to use Fields component to operate in the dependent fields but that hurts the performance of the decorated component as it provokes useless re-renders
It is also possible to connect the decorated component with redux and use formValueSelector that is provided by redux-form, but I wonder if there is a better approach to access a field(s) value.
Form Selectors and Field-dependent Values is described here. The solution is based on getFormValues:
import React from 'react';
import { connect } from 'react-redux';
import { reduxForm, getFormValues } from 'redux-form';
import FormComponent from './form.component';
export const FormContainer = props => {
const submitForm = (formValues) => {
console.log('submitting Form: ', formValues);
}
return (
<FormComponent
formValues={props.formValues}
change={props.change}
onSubmit={submitForm}
handleSubmit={props.handleSubmit}
/>
);
}
const mapStateToProps = state => ({
formValues: getFormValues('my-very-own-form')(state),
});
const formConfiguration = {
form: 'my-very-own-form',
}
export default connect(mapStateToProps)(
reduxForm(formConfiguration)(FormContainer)
);
and in your formComponent you can get the formValues from the props:
export const FormComponent = ({ handleSubmit, onSubmit, formValues }) => {
}

shall we use state or props for handling inputs in redux react?

I am confused with props or state to use here. If I use state in #connect I get error and does not work. when I use props it does not work with onchange handler to set new props. Please help how should I make input working with state or props. I am retrieving initial data from api.
import React, {PropTypes} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import { asyncConnect } from 'redux-async-connect';
import {load, isLoaded} from 'redux/modules/overview';
#asyncConnect([{
promise: ({ store: { dispatch, getState }, params: { id }, }) => {
const promises = [];
if (!isLoaded(getState())) {
promises.push(dispatch(load(id)));
}
return Promise.all(promises);
}
}])
#connect(
state => ({
overview: state.overview.data
}),
dispatch => bindActionCreators({load}, dispatch))
export default class Overview extends React.Component {
changeinput1(e) {
this.props.overview.title = e.target.value;
// changing value does not work here
}
constructor (props) {
super();
this.state = {
overview: null,
}
}
render() {
return (
<div>
<label>Input 1</label>
<input type="text" className="form-control" id="title" name="title" maxlength="35" value={this.props.overview.title} onChange={this.changeinput1.bind(this)}/>
</div>
)
}
}
I also want to do validation and want to save input value on onBlur so I dont want to use form.
if you want change reducer's(here suppose to be 'overview') value, you should define an action then dispatch it, not change it directly, the state get from store is readonly in the component

Resources