Redux-form loading indicator while auto saving - reactjs

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

Related

React Redux : saving and displaying data

I am trying to make a React app where I have a form and when submitted I want to show the data on the screen. I am also using redux. I am new to all that so I can't figure out how to save the data to the store and then display it.
If someone can tell me what I need to do. I think I should save the data from the form, pass it to the store but don't know how.
import React, { Component } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as actions from "../redux/actions";
export class AddAnimal extends Component {
state = {
animal: {
name: "",
animal: ""
}
};
onSubmit = e => {
console.log(e);
e.preventDefault();
};
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="text" name="name" />
<br />
<input type="text" name="animal" />
<br />
<input type="submit" value="submit" className="btn" />
</form>
);
}
}
const mapStateToProps = state => {
return {
animals: state.animals
};
};
const mapStateToDispatch = dispatch => {
return bindActionCreators(
{
addAnimal: actions.addAnimal
},
dispatch
);
};
export default connect(
mapStateToProps,
mapStateToDispatch
)(AddAnimal);
You are on the right track. you can locally save the form inputs data in a state Object inside the AddAnimal component such that it won't update redux state on every key change.
And on click of onSubmit you can dispatch an action (addAnimal which can be accessed by this.props.addAnimal) with form data as an argument. On dispatching it will call your reducer and save the data in the redux state.
As your AddAnimal component is listening on animals redux's state change. On updating redux state you can fetch newly updated data via props. (this.props.animals). But this will be only required if you want to show added data on UI inside the AddAnimal component.
Unnecessary mapStateToDispatch
in the component fix export to this:
export default connect(mapStateToProps, actions)(AddAnimal);
and you do not need mapStateToDispatch
and try to active the action with: this.props.addAnimal();

React-widgets DateTimePicker throwing error 'Cannot read property 'oneOfType' of undefined

I am using redux-forms and their example has a date time picker from react-widgets. Redux-Form react-widgets example
On the example on this page, it has a link to react-widgets. I pretty much followed the example on redux-forms site and I keep getting the following error:
TypeError: Cannot read property 'oneOfType' of undefined
./node_modules/react-widgets/lib/util/localizers.js
/node_modules/react-widgets/lib/util/localizers.js:23
Before anyone asks if Redux-Forms is setup correctly, I have this working with a couple of other render fields, I'm trying to add a date picker and it just crapped out on me.
// RenderDateTimePicker.jsx
import React from 'react';
import PropTypes from 'prop-types';
import DateTimePicker from 'react-widgets/lib/DateTimePicker';
import moment from 'moment';
import momentLocaliser from 'react-widgets/lib/localizers/moment';
momentLocaliser(moment);
const RenderDateTimePicker = ({input: { onChange, value, name }, label, outercss, inputcss, showTime}) => {
return (
<div className={outercss}>
<label htmlFor={name}>{label}</label>
<DateTimePicker onChange={onChange}
className={inputcss}
format={{ raw: 'MM/dd/yyyy'}}
defaultValue={new Date()}
time={showTime}
value={!value ? null : new DateTimePicker(value)}
/>
</div>
)
}
export default RenderDateTimePicker
// Snippet of main compoent
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import RenderTextField from '../common/RenderTextField';
import RenderDateTimeField from '../common/RenderDateTimePicker';
export class SearchBar extends Component {
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field name="startDt"
outercss="col-md-2"
inputcss="form-control form-control-sm"
label="Start Date"
component={RenderTextField}
/>
<Field name="endDt"
outercss="col-md-2"
inputcss="form-control form-control-sm"
label="End Date"
component={RenderDateTimeField}
/>
<button className="btn btn-primary">Search</button>
</form>
)
}
}
export default reduxForm({
form: 'SerchAppDeploymentForm'
})(
connect(mapStateToProps, mapDispatchToProps)(SearchBar)
);

How to access redux form values in another component

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

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