How to access redux form values in another component - reactjs

I using Redux-Form 7.3.0. I am trying to get the values of my form in another component. I read the instruction at the website of Redux form but didn't work.
this is the code of my componenet:
import React from 'react'
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { formValueSelector } from 'redux-form';
class Test extends React.Component {
render() {
console.log(this.props);
return (
<div>
test
{this.props.title}
</div>
);
}
}
const selector = formValueSelector('NewPostForm');
Test = connect(
state => ({
title: selector(state, 'title')
})
)(Test)
export default Test;
This is my form component:
import React from 'react';
import { Field, reduxForm } from 'redux-form';
class NewPost extends React.Component {
renderField(field) {
return (
<div>
<label>{field.label}</label>
<input type="text" {...field.input} />
</div>
);
}
showResults(values) {
window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`);
}
render() {
const { pristine, submitting, handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.showResults)} >
<div>
<Field
label='Title'
name='title'
component={this.renderField}
/>
<button type='submit' disabled={submitting}>
Submit the from :)
</button>
</div>
</form>
);
}
}
export default reduxForm({ form: 'NewPostForm'})(NewPost);
but I always get
title:undefined
I found the same question here but it did not help me.

Your Test component has two imports from "redux-form". Please make it just one, like this:
import { Field, reduxForm, formValueSelector } from 'redux-form'
If your NewPost component gets unmounted at any moment, maybe by changing view or something during a navigation, the state of the form gets destroyed. You can avoid such default behavior by adding destroyOnUnmount attribute with a false value to your reduxForm wrapper:
export default reduxForm({
form: 'NewPostForm',
destroyOnUnmount: false
})(NewPost)
If this doesn't help you, please provide a better context of how you're using your components.
UPDATE: I made an example where I define 4 components:
NewPost.js: It's the form connected to the store with redux-form.
ShowPost.js: Shows what was captured (the post) by the form when you hit the submit button. This data is set to the NewPost internal state, and then it's passed as prop.
ShowPostFromSelector.js: Shows what is being captured by the form, this due to the use of the selector formValueSelector.
App.js: It's the container of the 3 components above, where the onSubmit function is defined.
Here it is: https://codesandbox.io/s/w06kn56wqk

Related

Redux-form loading indicator while auto saving

I am working on a react app that similar minimal version of google docs. I am using a redux form with two fields title and content and also doing auto-submitting data on a change to inputs.
How do I implement a feature that showing Saving while typing and Saved when done submitting?
// file: AutoSaveForm.js
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form'
import _debounce from 'lodash.debounce'
class AutoSaveForm extends Component {
render() {
const { handleSubmit, submitting } = this.props
return (
<form onSubmit={handleSubmit}>
<Field name="title" component="input" />
<Field name="content" component="textarea" />
<button type="submit" disabled={submitting}>
Submit
</button>
</form>
)
}
}
export default reduxForm({
form: 'auto_save_form',
onChange: _debounce((values, dispatch, props, previousValues) => {
props.submit()
}, 800)
})(AutoSaveForm)
You can listen to redux-form actions (change, blur, array changes ..etc) using redux-saga or create a custom redux middleware
redux-form exports all of its action type, you can import like this:
import { actionTypes } from 'redux-form';
in your saga handler/middleware you can programmatically submit the form by dispatching submit action
For Saving and Save status you can use isSubmitting, isDirty redux-form selector

using prompt of react-router in componentWillUnmount

i have a parent component which renders a custom form, i am using redux form on the custom form, what i am trying to do is whenever the child component gets unmounted if there are any values on the form i need to make a prompt to the user do you want to save it or not.
So below is the code, the prompt is not happening, i am using the state and updating the state using dirty(this.props) of redux form.
so after componentWillUnmount the render is not happening. What i am missing, i think after componentWillUnmount the render won't happen.
Please see the below code.
**//APP.js**
import React from 'react';
class App extends Component{
state ={
data = []// array of data
}
render(){
return(
<div>
<CustomForm
data={this.state.data}
/>
</div>
)
}
}
export default App
**//CustomForm.js**
import React from 'react';
import {connect} from 'react-redux';
import CustomField from './CustomField';
import { Field, reduxForm } from 'redux-form';
import {Prompt} from 'react-router'
class CustomForm extends Component{
state ={
formChanged: false
}
onSubmit = (values) => {
console.log(values)
}
componentWillUnmount(){
if(this.props.dirty){
this.setState({
formChanged: true
})
}
}
render(){
return(
<div>
{
this.state.formChanged?
<Prompt
when={shouldBlockNavigation}
message='You have unsaved changes, are you sure you want to leave?'
/>
:
null
}
<Form onSubmit={handleSubmit(this.onSubmit)}>
<Field
name="field1"
type="text"
component={CustomField}
label="field1"
/>
</Form>
</div>
)
}
}
export default reduxForm({
form: "NewForm",
destroyOnUnmount: true,
forceUnregisterOnUnmount: false
})(connect(mapStateToProps, mapDispatchToProps)(CustomForm))

Dispatch is not a function react redux

I have a react component that will throws an error when I try to dispatch a redux action. Here is the component:
import React from 'react';
import { connect } from 'react-redux';
import { createBook } from './actions/books';
import './InputForm.css';
export class InputForm extends React.Component {
onFormSubmit(event) {
event.preventDefault();
let newBook = {
title: this.titleInput.value,
author: this.authorInput.value,
description: this.descriptionInput.value
}
this.props.dispatch(createBook(newBook));
}
render() {
return (
<div>
<form onSubmit={event => this.onFormSubmit(event)}>
<input className="form-input" placeholder="Title" ref={input => this.titleInput = input} />
<input className="form-input" placeholder="Author" ref={input => this.authorInput = input} />
<input className="form-input form-text-area" placeholder="Description" ref={input => this.descriptionInput = input} />
<button className="form-button" type="submit">Submit</button>
</form>
</div>
)
}
}
export default connect()(InputForm);
This is the line that creates the problem:
this.props.dispatch(createBook(newBook));
I'm not sure what's going on. Here is the error I get:
Uncaught TypeError: this.props.dispatch is not a function
at InputForm.onFormSubmit (InputForm.js:15)
at onSubmit (InputForm.js:21)
at HTMLUnknownElement.callCallback
I have another component set up almost identically using a different action. It works fine. Here is that component if anyone wants to compare:
import React from 'react';
import './Book.css';
import { deleteBook } from './actions/books';
import { connect } from 'react-redux';
export class Book extends React.Component {
onDelete(event) {
this.props.dispatch(deleteBook(this.props.id));
}
render() {
return (
<div className="book-container">
<h4>{this.props.title}</h4>
<p>{this.props.author}</p>
<p>{this.props.description}</p>
<p>{this.props.id}</p>
<button className="book-delete-button" onClick={event => this.onDelete(event)}>Delete</button>
</div>
)
}
}
export default connect()(Book);
Dunno what's going on here. Please help!
Seems like there at least 2 issues here that can cause a problem.
It depends on how you import the components. You are exporting 2
components in each module:
A named export (the component)
And a default export (the new connected component).
If you import the named export:
import { InputForm } from './path';
You will not have the redux related props as this is not the
connected component.
This is why one of your other connected components is working fine even though it seems to have the same code and structure pattern.
You probably import it the way you should (default import).
Make sure you import the default component:
import InputForm from './path';
Another thing that caught my eye, is that you are not binding the
event handler onFormSubmit, so i expect the this to be the
element that triggered the event. Though i think if that was the
issue, you would get a different error anyway.
I had imported the disconnected version in the container component. Stupid mistake.

Unable to capture Redux-form Field values with handleSubmit

I am trying to integrate Redux-form v6 into my project, however no matter how closely I try to replicate the example code, I cannot get a working redux-form.
Everything seems to be connected properly, however the handleSubmit function does not capture any of the values from my form fields.
Any guidance on this issue would be greatly appreciated. My code is below.
Starting with the reducer, nothing seems to be the matter here.
import { reducer as formReducer } from 'redux-form';
export default combineReducers({
form: formReducer
});
Then, I use a container component to connect the form component to redux form, which decorates the form component nicely with all the Redux-form function.
CreateCompany.js
import CreateCompany from '../components/create_company';
import { reduxForm } from 'redux-form';
export default reduxForm({
form: 'company-submission'
})(CreateCompany);
The actual form then looks like this:
CreateCompany.jsx
<form onSubmit={ handleSubmit(values => {console.log("values",values)})}>
<div>
<label htmlFor="group">Group Name (Required)</label>
<Field name="group" component={FormInput} type="text"/>
</div>
<div>
<Field
name="group-type"
component={DropDownSelect}
selectOptions={this.state.groupTypes}
id="group-type"
/>
<label>Group Type</label>
</div>
<button type="submit">Log In</button>
</form>
The text input stateless functions supplied to the Field component.
FormInput.js
(Note: I had to include {...input.value} in the input tag to be able to type into the field. In the example code, only {...input} is used.)
import React from 'react';
const FormInput = ({ id, type, className, input }) => {
className = className || "";
id = id || "";
return (
<input id={id} {...input.value} type={type} className={className}/>
)
}
export default FormInput;
DropDownSelect.js
import React from 'react';
const DropDownSelect = ({ input, selectOptions, id }) => {
const renderSelectOptions = (selectOption) => (
<option key={selectOption} value={selectOption}>{selectOption}</option>
)
return (
<select id={id} {...input}>
{selectOptions.map(renderSelectOptions)}
</select>
);
}
export default DropDownSelect;
Any idea what I am doing wrong?
handleSubmit should be defined outside of you CreateCompany component and passed to it via props. Check out examples

can't type in input fields when using material-ui-redux-form due to re rendering

I'm using material-ui with redux. For some reason I can't type in my input fields whenever I follow the example provided at http://redux-form.com/6.2.0/examples/material-ui/ .
After using chrome redux dev tool I noticed that the state of the inputs is changing when I type but then it's re-rendering the entire component whenever something is typed, which makes it seem like nothing is being typed. Oddly enough, this only occurs when I use the Field component, as is used in the examples. If I just use material-ui components, the form allows typing and it doesn't re render. I've included the entire code to my component. Any help is much appreciated! What am I doing wrong?
import React, { Component } from 'react'
import {Field, reduxForm} from 'redux-form'
import { TextField } from 'redux-form-material-ui'
import RaisedButton from 'material-ui/RaisedButton'
class Login extends Component {
constructor (props) {
super(props)
this.handleFormSubmit = this.handleFormSubmit.bind(this)
}
componentDidMount () {
console.log(this.refs)
this.refs.username // the Field
.getRenderedComponent() // on Field, returns ReduxFormMaterialUITextField
.getRenderedComponent() // on ReduxFormMaterialUITextField, returns TextField
.focus() // on TextField
}
handleFormSubmit ({ username, password }) {
console.log(username, password)
}
render () {
const {
handleSubmit,
pristine,
submitting,
input,
fields: { username, password }
} = this.props
return (
<div className='loginWrapper'>
<form onSubmit={handleSubmit(this.handleFormSubmit)}>
<div id='loginNotch' />
<h1 className='loginHeader'>Login</h1>
<div>
<Field
component={TextField}
name='username'
floatingLabelText='Username'
ref='username' withRef />
</div>
<div>
<Field
component={TextField}
type='password'
name='password'
floatingLabelText='Password'
ref='password' withRef />
</div>
<div>
<RaisedButton
label='Go'
primary />
</div>
</form>
</div>
)
}
}
// TODO: keep property names consistent with server
export default reduxForm({
form: 'login',
fields: ['username', 'password']
})(Login)
Update: I took a look at the docs and removed fields from the export, and it is still not working.
You can clone project from here https://bitbucket.org/kvoth3/loanpayments.git
it's just a simple login screen
Try changing your reducer to
const rootReducer = combineReducers({
form: authReducer
})
ReduxForm expects your redux state structure to be
{
form: {
formName: {}
}
}
If you need to use a different name other than form, you need to provide a getFormState(state) to the reduxForm() decorator.

Resources