React - Redux-Form Remote Submit - javascript

I am attempting to remotely submit a form using redux-forms. My question would be, how do I execute redux actions from a function outside the component. The equivalaent of saying:
this.props.action(params);
My code is as follows:
async function submit(values) {
return (
//Equivalent of => this.props.addOne(values.name)
await actions.addOne(values.name, 60)
)
}
const renderTextField = ({ input, label, meta: { touched, error } }) =>
<TextField
autoFocus
margin="dense"
fullWidth
type="text"
label={label}
{...input}
/>
class LibrarySubsectionForm extends React.Component {
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
component={renderTextField}
name="name"
label="Subsection Name"
/>
</form>
)
}
}
export default compose(
connect(null, actions),
reduxForm({ form: 'AddSubsection', onSubmit: submit })
)(LibrarySubsectionForm);

Redux-form is passing dispatch function and props of your decorated component as second and third arguments of onSubmit handler. So basically you have access to them inside your submit function. If you are passing actions as a prop to LibrarySubsectionForm then you can access them inside submit function:
async function submit(values, dispatch, props) {
return await props.actions.addOne(values.name, 60);
}

Related

React on Rails: Can't enter text in my form input boxes

When I try to type in the boxes on the webpage it doesn't register that I am typing anything. I am guessing it has something to do with the handleChange or onChange, but I could use some help here. I am still pretty new to React and trying to figure it out. What am I missing here?
import React, {Component} from 'react';
import { Form } from 'semantic-ui-react';
class Assessments extends Component {
state = {assessment_name: '', assessment_type: ''}
componentDidMount() {
if (this.props.id) {
const { assessment_name, assessment_type } = this.props
this.setState({ assessment_name, assessment_type })
}
}
handleChange = (a) => {
const { name, value } = a.target
this.setState({ [name]: value })
}
handleSubmit = (a) => {
a.preventDefault()
if (this.props.id) {
const { id, history } = this.props
this.props.updateName(id, this.state, history)
this.props.toggleUpdate()
}
this.props.close()
this.setState({ assessment_name: '', assessment_type: ''})
}
close = () => this.setState({ open: false })
render() {
const { assessment_name, assessment_type } = this.state
return(
<Form onSubmit={this.handleSubmit}>
<Form.Input
name=''
value={assessment_name}
onChange={this.handleChange}
label='Assessment Name'
required
/>
<Form.Input
name='AssessmentType'
value={assessment_type}
onChange={this.handleChange}
label='Assessment Type'
required
/>
<Form.Button>Submit</Form.Button>
</Form>
)
}
}
export default Assessments;
You're not passing the right names to the Form.Input components which the handleChange function uses to update the state. They have to be 'assessment_name' and 'assessment_type' respectively to make sure the state gets updated on input change events and the new values get reflected on the fields.
<>
<Form.Input
name="assessment_name"
value={assessment_name}
onChange={this.handleChange}
label="Assessment Name"
required
/>
<Form.Input
name="assessment_type"
value={assessment_type}
onChange={this.handleChange}
label="Assessment Type"
required
/>
</>

I am unable to pass props from parent to child in React

Starting out with react, I have created an input field in the parent component, When the user submits the text, I am passing down the text to the child component and printing the text under the parent component.
Code of parent component
import React, { useState } from "react";
import Validate from "./Validate";
function CommandEntry() {
const [value, setValue] = useState("");
const handleSubmit = e => {
e.preventDefault();
// console.log(value);
return <Validate value={value} />;
};
return (
<div>
<form onSubmit={handleSubmit}>
enter text:~
<input
type="text"
autoFocus
required
onChange={e => setValue(e.target.value)}
/>
</form>
</div>
);
}
export default CommandEntry;
Code of child component
import React from "react";
export default function Validate(props) {
console.log("I am in child");
return (
<div>
<h1>{props.value}</h1>
</div>
);
}
You would need to render the child inside return and the set the value in handler.
Like so:
function CommandEntry() {
const [value, setValue] = useState("");
const [submit, setSubmitValue] = useState(false);
const handleChange = e => {
e.preventDefault();
setValue(e.target.value); //setting the value on change
};
const handleSubmit = e => {
e.preventDefault();
setSubmitValue(true); //setting the submit flag to true.
};
return (
<div>
value &&
<form onSubmit={handleSubmit}> // submit handler
enter text:~
<input
type="text"
autoFocus
required
onChange={handleChange} // change handler
/>
{submit &&
<Validate value={value} /> // rendering the child component
}
</form>
</div>
);
}
You can't return a JSX element from a handler function. Handler functions are different and render functions are different. So here you can change this in your parent component in which child will be shown only when submit is true.
import React, { useState } from "react";
import Validate from "./Validate";
function CommandEntry() {
const [value, setValue] = useState("");
const [submit, setSubmitValue] = useState(false);
const handleSubmit = e => {
e.preventDefault();
setSubmitValue(true);
};
return (
<div>
<form onSubmit={handleSubmit}>
enter text:~
<input
type="text"
autoFocus
required
onChange={e => setValue(e.target.value)}
/>
</form>
{submit && <Validate value={value} />}
</div>
);
}
export default CommandEntry;

How to display the state on the same page when clicked Submit button in react

I have made a form in react which takes input from the user and stores it in the state. Now, I want to display the state values when the user clicks Submit button in an input field just below the submit button in React.
Im new to react.
You have to make an object (E.g. Credentials) and when someone clicks the button, credential takes the props of the state like this:
App.js
//import code....
import Form from './Form.js'
//class app code.....
//in the render method:
render() {
return (
<Form />
)
}
Form.js
// import code ....
state = {
firstName: '', // or what you want
lastName: '', // or what you want
email: '', // or what you want
send: false,
}
//handleChange function
const handleChange = (event) => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
//handleClick function
const handleClick = () => {
this.setState({send: true})
}
In the Render method
render() {
return (
<div>
<input name='firstName' onChange={handleChange} />
<input name='lastName' onChange={handleChange} />
<input name='email' onChange={handleChange}/>
<button onClick={handleClick}>Send</button>
{send &&
<Credentials
firstName={this.state.firstName}
lastName={this.state.lastName}
email={this.state.email}
/>
}
</div>
)
}
export default Form // or your file's name
In the Credential.js
//import code...
const Credentials = ({firstName, lastName, email}) => {
return (
<h2>firstName is: {firstName}</h2>
<h4>lastName is: {lastName}</h4>
<p>email is: {email}</p>
)
}
export default Credentials
In React you can use 'useState' to initiate a number or any kind of input. Then set that number when the user clicks on a button.
import React, { useState } from "react";
function App() {
const [number, setNumber] = useState();
let typedNumber = 0;
const btnHandler = (e) => {
e.preventDefault();
setNumber(typedNumber);
};
return (
<div>
<form onSubmit={btnHandler}>
<input type="text" onChange={(e) => (typedNumber = e.target.value)} />
<input type="submit" />
</form>
<p>{number}</p>
</div>
);
}
export default App;

Abstract client for <ApolloConsumer>

I'm using Formik to validate form data. As additional validation, I check if the user email exists in the database. I have this code working but I don't like having it inline. Is there a better way to write this so validation doesn't have to be inline? I don't understand how to pass the client through.
<Form className="form">
<ApolloConsumer>
{client => (
<Field className="text-input" type="email" name="email" placeholder="Email" validate={async (value) => {
let error
const response = await client.query({
query: USER_EXISTS,
variables: {
query: value
}
})
console.log(response.data.userExists)
if (response.data.userExists) {
error = 'Email taken'
}
return error
}} />
)}
</ApolloConsumer>
<Form>
For example, something like this:
<ApolloConsumer>
{client => (
<Field className="text-input" type="text" name="username" placeholder="Username" validate={this.validateUsername(client)} />
)}
</ApolloConsumer>
validateUsername = async (value, client) => {
let error
const response = await client.query({
query: USER_EXISTS,
variables: {
query: value
}
})
console.log(response.data.userExists)
if (response.data.userExists) {
error = 'Username taken'
}
return error
}
It seems like you need a HOC (High Order Component) is a function that return a component, so to abstract your function you need something like
const withApolloClient = (ConnectedComponent) => class extends React.Component {
render() {
return (
<ApolloConsumer>
{client => <ConnectedComponent {...this.props} client={client} />
</ApolloConsumer>
);
}
}
once you have setup your withApolloClient HOC, so you can use it as follow
// create a field component with validation logic
class FieldWithValidationApolloClient extends React.Component {
async validateUsername() {
let error;
const { client, field } = this.props; // get apollo client injected by withApolloClient Hoc
const { value } = field; // get value from the field
const response = await client.query({
query: USER_EXISTS,
variables: {
query: value
}
})
console.log(response.data.userExists)
if (response.data.userExists) {
error = 'Username taken';
}
return error;
}
render() {
return (
<Field {...this.props} validate={this.validateUsername(client)} />
);
}
}
And finally just implement your component
// import your withApolloClient component file
import withApolloClient from './withApolloClient';
import FieldWithApolloClient from './FieldWithValidationApolloClient';
const FieldWithApollo = withApolloClient(FieldWithApolloClient);
class YourFormComponent extends React.Component {
render() {
return (
<form>
<FieldWithApollo className="text-input" type="text" name="username" placeholder="Username" />
</form>
);
}
}
<form>
</form>
remember that {...this.props} will spread all the attributes declare into the tag component
Hope it can help you.

Pass initial value to redux-form

I want to pass initial values (coming from the props of a react-redux component) to my redux-form. But, I get not value when I inspect the data passed to the renderField . I followed the posts here in SO and on redux-form git forum, and I'm using initialValues in mapStateToProps but still it doesn't work.
This is my react-redux component which holds the redux-form:
class ShowGroup extends Component {
render() {
if (this.state.loading) {
return <div>Loading group ....</div>;
}
if (this.state.error) {
return <div>{this.state.error}</div>;
}
let group = this.props.groups[this.groupId];
return (
<div className="show-group">
<form>
<Field
name="name"
fieldType="input"
type="text"
component={renderField}
label="Name"
validate={validateName}
/>
</form>
</div>
);
}
}
function mapStateToProps(state) {
return {
groups: state.groups,
initialValues: {
name: 'hello'
}
};
}
const mapDispatchToProps = (dispatch) => {
return {
//.....
};
};
export default reduxForm({
form:'ShowGroup'
})(
connect(mapStateToProps, mapDispatchToProps)(ShowGroup)
);
This is my renderField code:
export const renderField = function({ input, fieldType, label, type, meta: { touched, error }}) {
let FieldType = fieldType;
return (
<div>
<label>{label}</label>
<div>
<FieldType {...input} type={type} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
}
You are exporting the wrapped component with incorrect order
export default reduxForm({
form:'ShowGroup'
})(
connect(mapStateToProps, mapDispatchToProps)(ShowGroup)
);
should be
export default connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form:'ShowGroup'
})(ShowGroup);
The reason being that the redux form HOC needs the initialValues prop for itself, if you reverse the order, reduxForm doesn't get the props rather they are passed directly to the component, which doesn't know what to do with it.

Categories

Resources