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)));
Related
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.
I'm a newbie to the react-redux world, please correct me if I'm missing something:
Basically I'm trying to access the hostname via redux store and use it inside the form. As of now I'm just using the hostname reference window.location within the redux form but I would like to access the hostname via the redux store/ via any other better approach so I can keep the function pure? Thoughts?
Thanks
Edit:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
const SimpleForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
// goal is to prevent this here and do it via redux store or
// any other options
// so I can avoid external calls inside pure function
const hostName = window.location.hostname;
return (
<form onSubmit={handleSubmit}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name"/>
</div>
</div>
</form>
)
}
export default reduxForm({
form: 'simple' // a unique identifier for this form
})(SimpleForm)
Question:
How can I store the window objects in the redux store and is it possible to access them in the redux forms via redux store or would react router help by any chance?
You should connect your form to the Redux state.
import { connect } from 'react-redux'
export default reduxForm({
form: 'simple' // a unique identifier for this form
})(connect(mapStateToProps)(SimpleForm)
and then:
const mapStateToProps = state => {
return {
hostName: state.reducerName.hostName
}
}
so you can access it through this.props.hostName, considering that hostName is set in the reducer previously.
If you are using React Router, you can access the history object through props, which also has the location property.
The previously mentioned answer did now work for me sadly,
Here is what worked for me, reference to react-redux doc
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
form: state.form
}
}
ClassName= connect(
mapStateToProps,
mapDispatchToProps
)(ClassName);
export default reduxForm({
form: 'ObjectRepo',
validate: validateObjects
})(ClassName);
The 'validate' that im passing is my validation.js, since i am using sync validations (if you have any, its completely optional)
'form' is the name of state i have used in my reducer. My reducer code,
const allReducers = combineReducers({
form: reduxFormReducer
});
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 }) => {
}
I am able to render an input field using redux-form, but I can't seem to type any text inside the field (the component seems to re-render with each keystroke). Below is the code, I created a really simple one to try to pinpoint the problem:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createStore, combineReducers } from 'redux';
import { Field, reduxForm, reducer as formReducer } from 'redux-form';
const reducers = {
// ... your other reducers here ...
form: formReducer // <---- Mounted at 'form'
};
const reducer = combineReducers(reducers);
const store = createStore(reducer);
class TestForm extends Component {
formSubmit(props) {
console.log('form submitted');
}
render() {
const { handleSubmit } = this.props;
return (
<div>
This is a test form.
<div>
<form onSubmit={handleSubmit(this.formSubmit.bind(this))}>
<Field name="firstField" component="input" type="text" />
<button type="submit">Submit</button>
</form>
</div>
</div>
);
}
}
TestForm = reduxForm({
form: 'testingForm'
})(TestForm);
export default TestForm;
I also literally copied and pasted the example from the official redux-form docs: http://redux-form.com/6.0.2/docs/MigrationGuide.md/ and I still encounter the same problem. Been trying to figure this out for some hours now. Could it be the version of redux or redux-form?
I'm using redux v3.5.2 and redux-form v6.2.1.
Would appreciate any help!
I had the same issue. The cause was that I failed to add the formReducer to the list of reducers I was using. To fix I added:
import { reducer as formReducer } from 'redux-form'
const RootReducer = combineReducers({
...
form: formReducer // <---- Mounted at 'form'
})
I think you need to look into the react-redux docs. This component needs to be placed inside a <Provider store={store}> component. Perhaps you are doing that outside this file and have just included the store initialization to be informative?
I'm using Redux Form (ver. 6) for a log in page. What I would like to do is when the user fills out the form and clicks submit, grab the text from my state so that I can eventually dispatch an action with that email and password. However, I'm having trouble with exporting this component while using both connect from react-redux and Redux Form.
Using react-redux, connect wants to be exported like so when mapping state to props:
export default connect(mapStateToProps)(LogInForm)
However, Redux Form wants it's export set up like this:
export default reduxForm({
form: 'LogInForm',
validate,
})(LogInForm);
Is there a way to combine these two? I'd tried something like:
const reduxFormConfig = reduxForm({
form: 'LogInForm',
validate,
});
export default connect(mapStateToProps)(ReduxFormConfig)(LogInForm)
but it did not work.
Or Perhaps that's a better approach to handling this? Here is the full code from within my component:
import React from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import InputField from '../InputField';
import { validateLogInSignUp as validate } from '../../utils/validateForms.js';
const LogInForm = (props) => {
const {
handleSubmit,
pristine,
submitting,
} = props;
return (
<div>
<form onSubmit={handleSubmit}>
<Field
name="email"
type="email"
component={InputField}
label="email"
/>
<Field
name="password"
type="password"
component={InputField}
label="password"
/>
<div>
<button type="submit" disabled={submitting}>Submit</button>
</div>
</form>
</div>
);
};
const mapStateToProps = state => {
return {
loginInput: state.form,
};
};
// export default connect(mapStateToProps)(LogInForm)
// export default reduxForm({
// form: 'LogInForm',
// validate,
// })(LogInForm);
Any and all help is much appreciated. Thanks!
There still a way to combine these two in reduxForm v6:
reduxForm({
form: 'LogInForm',
validate,
})(LogInForm);
export default connect(mapStateToProps)(LogInForm)
Here is how:
import React, { Component } from 'react';
import { connect } from 'react-redux
class LogInForm extends Component {
...
}
function mapStateToProps(state) {
return { ... }
}
function mapDispatchToProps(dispatch) {
return { ... }
}
// First decorate your component with reduxForm
LogInForm = reduxForm({
form: 'LogInForm',
validate,
})(LogInForm);
// Then connect the whole with the redux store
export default connect(mapStateToProps, maDispatchToProps)(LogInForm)
Using redux-form you shouldn't need to access the state directly in your LoginForm. Instead, you should access the values in your parent component when the form is submitted:
// LoginForm.js
const LogInForm = (props) => {
...
};
export default reduxForm({
form: 'LogInForm',
validate,
})(LogInForm);
// Parent.js
import LoginForm from './LoginForm';
const handleSubmit = (values) => {
alert(JSON.stringify(values)); // { email: 'foo#bar.com', password: '1forest1' }
};
const Parent = (props) => {
return (
<LoginForm onSubmit={ handleSubmit } />
);
};
See https://github.com/erikras/redux-form/blob/master/examples/simple/src/index.js#L42 for a more complete example of a simple form.
You can try this :
import React from 'react';
import { connect } from 'react-redux' ;
import { reduxForm } from 'redux-form';
class Example extends React.Component {
...
}
function mapStateToProps(state) {
return { ... }
}
function mapDispatchToProps(dispatch) {
return { ... }
}
export default connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form: 'formname',
validate
})(Example));
There are multiple threads with same issue. I recently posted my take with my solution here but with a few variations.
I used a class based component than a function based. I have found guides to specifically implement that way and explaining that the connect method of react-redux make it a Higher Order Component and as such it is best used with a class instance.
As mentioned by #doncredas, reduxForm and react-redux's connect method should be implemented separately, however, my implementation is as follows:
function mapStateToProps(state) {
return { form: state.form };
}
Signin = connect(mapStateToProps, actions)(Signin);
Signin = reduxForm({
form: 'signin'
})(Signin);
export default Signin;
[Added later] Another variation can be:
const form = reduxForm({ form: 'signin' });
export default connect(mapStateToProps, actions)(form(Signin));