Problem connect Redux with parent props from React - reactjs

I have been trying for several days to solve a problem between connect of redux and a props of a parent component. I use redux in my child component and at the same time use props to call a handlechange function and a state of the parent component.
When in the child component use connect does not update this.props.args properly, however in the parent there is no problem. Then I have a validation so that when all the fields are complete, my submit button will be activated.
Additionally implement a state and a function in the parent component to detect the movement of the mouse and pass it to the child component, to clear some doubts, the amazing thing is that in this case if it detects changes in this.props.mouse and much more rare is that when I fill a field and then move the mouse, my this.props.args in the child component if it is updated. I'm a little disconcerted and I do not know what is due.
Parent Component:
import React, { Component } from "react";
import SignUp from './login/SignUp';
class Login extends Component {
state = {
showRegister: true,
argsSignup: {},
move: {},
}
handleChange = (ev, input) => {
let argsSignup = this.state.argsSignup;
argsSignup[input.name] = input.value;
this.setState({argsSignup});
//console.log(this.state.argsSignup);
}
handleMouseMove = (event) => {
this.setState({
move: {
x: event.clientX,
y: event.clientY
}
});
}
render() {
const {showRegister, argsSignup, move} = this.state;
return(
<div onMouseMove={this.handleMouseMove}>
{showRegister && <SignUp args={argsSignup} handleChange={this.handleChange} mouse={move} />}
</div>
);
}
}
export default (Login);
Child Component (with connect):
import React, { Component } from "react";
import { connect } from "react-redux";
import { Form, Button } from 'semantic-ui-react';
import { signInFacebook } from "../../redux/createActions";
class SignUp extends Component {
render() {
const {args, handleChange, signInFacebook} = this.props;
return(
<React.Fragment >
<Form >
<Form.Field>
<Form.Input name='email' onChange={handleChange} placeholder='numero de movil o correo electronico' />
</Form.Field>
<Form.Field>
<Form.Input name='name' onChange={handleChange} placeholder='Nombre completo'/>
</Form.Field>
<Form.Field>
<Form.Input name='username' onChange={handleChange} placeholder='Nombre de usuario' />
</Form.Field>
<Form.Field>
<Form.Input name='password' onChange={handleChange} type="password" placeholder='contraseña' />
</Form.Field>
<Button
type='submit'
disabled={!args.email || !args.username || !args.name || !args.password }
primary
fluid>
Regístrate
</Button>
</Form>
<button onClick={signInFacebook}>Inicia sesion con Facebook</button>
</React.Fragment>
)
}
}
export default connect(null, {signInFacebook})(SignUp);
On the other hand, if I delete the connect from my child component, everything works great and if it detects the changes of this.props.args
Child Component (without connect):
import React, { Component } from "react";
import { connect } from "react-redux";
import { Form, Button } from 'semantic-ui-react';
import { signInFacebook } from "../../redux/createActions";
class SignUp extends Component {
render() {
const {args, handleChange, signInFacebook} = this.props;
return(
<React.Fragment >
<Form >
<Form.Field>
<Form.Input name='email' onChange={handleChange} placeholder='numero de movil o correo electronico' />
</Form.Field>
<Form.Field>
<Form.Input name='name' onChange={handleChange} placeholder='Nombre completo'/>
</Form.Field>
<Form.Field>
<Form.Input name='username' onChange={handleChange} placeholder='Nombre de usuario' />
</Form.Field>
<Form.Field>
<Form.Input name='password' onChange={handleChange} type="password" placeholder='contraseña' />
</Form.Field>
<Button
type='submit'
disabled={!args.email || !args.username || !args.name || !args.password }
primary
fluid>
Regístrate
</Button>
</Form>
<button onClick={signInFacebook}>Inicia sesion con Facebook</button>
</React.Fragment>
)
}
}
export default (SignUp);
I appreciate your help from now on. Thank you!!

When you connect your component, you are establishing a connection with Redux and the props of that component will be fed by the entire application state.
export default connect(mapStateToProps, {signInFacebook})(SignUp);
Your first parameter for connect function holds the mapStateToProps function which essentially maps the application state to props of the SignUp component. Keeping that null means that you're expecting a null state object from Redux and hence you are unable to get the desired result in this.props.args. Removing connect statement makes the props which are passed down to the child component accessible through this.props. That's the crux of Redux.

Related

Using input state in different components

I want to use the state of the input in another component in React. So I have a component and in this component, I have a form.
import React, { useState } from "react";
import { Form } from "react-bootstrap";
function Jumbotron() {
const [inputFrom, setInputFrom] = useState("");
return (
<Form className="shadow p-3 mb-5">
<Form.Group controlId="formGroupFrom">
<Form.Label className="form-subtitle">Title</Form.Label>
<Form.Control
type="text"
placeholder="Enter input"
onChange={(event) => setInputFrom(event.target.value)}
/>
</Form.Group>
</Form>
);
}
export default Jumbotron;
So I want to use the 'inputFrom' in other component and I just want to show it. I will do it in several components so could you give me an advice about it?
import React from "react";
import { Container } from "react-bootstrap";
function Checkout() {
return (
<Container>
<div className="shipment-info">
<div className="basic">
<div className="col-2 title">From</div>
<div className="col-4 info">{inputFrom}</div>
</div>
</div>
</Container>
);
}
export default Checkout;
You can pass down the prop to another component like so
<NextComponent propYouWantToPass={inputFrom} />
and use it in the next component like props.propYouWantToPass, assuming you got the props in the next component settings props as a parameter
const NextComponent = (props) => {
return(
<View>
<Text>{props.propYouWantToPass}</Text>
</View>
)
}
As other already said, if you are planning to use Checkout component inside Jumbotron component as a child.
The solution is easy, you just pass inputForm as prop to Checkout and receive or inherit from Jumbotron
Could be something like this:
import React, { useState } from "react";
import { Form } from "react-bootstrap";
import { Checkout } from "./Checkout";
function Jumbotron() {
const [inputFrom, setInputFrom] = useState("");
return (
<>
<Form className="shadow p-3 mb-5">
<Form.Group controlId="formGroupFrom">
<Form.Label className="form-subtitle">Title</Form.Label>
<Form.Control
type="text"
placeholder="Enter input"
onChange={(event) => setInputFrom(event.target.value)}
/>
</Form.Group>
</Form>
{/* <-- give any name instead "inputData" */}
<Checkout inputData={inputForm} />
</>
);
}
export default Jumbotron;
Found your inputForm on Checkout as props.inputData
*Ref: https://reactjs.org/docs/components-and-props.html#rendering-a-component

Input react wrapper

I want to make a form for user data and I was asked to make a wrapper react components for each type of input. My problem is passing the handler to the input component.
This is my form:
import React from 'react';
import {addUser as addNewUser} from '../../services/index';
import {TextBox} from './TextBox'
interface AddUserProps{
}
interface AddUserState{
UserName:string,
}
export default class AddUser extends React.Component<AddUserProps, AddUserState> {
constructor(props:any) {
super(props);
this.state = {
UserName: '',
};
this.updateUserName = this.updateUserName.bind(this);
}
updateUserName(event: React.ChangeEvent<HTMLInputElement>) {
this.setState({UserName: event.target.value});
}
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(this.state)
addNewUser(this.state)
}
render() {
return (
<div>
<form
className = "user-add-form"
onSubmit={(event) => this.handleSubmit(event)}
>
<h3>Adauga utilizatori:</h3>
<label htmlFor="userName">User Name:</label>
<TextBox name="userName" type="text" value={userName} handleChange={this.updateUserName}/>
<input type="submit" value="Add user"/>
</form>
</div>
)
}
}
export {AddUser};
And this is the input component that I made:
import React from 'react'
export function TextBox(props) {
return (
<div>
<input type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.HandleInput(event)}
/>
</div>
)
}
So what I don't know is how to pass the event handler to the input component, because as it is right now it can't find it.
It should exist in Textbox's props as handleChange as it's passed in the parent component. Does this not work?
<input
type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.handleChange(event)}
/>

react-hook-form access to validation rules in nested component

I'd like to access to the validation rules defined in react-hook-form's Resister in the nested component to dynamically display required indicator(*).
Is there a way to access from Nested component?
I don't want to repeat by passing as a prop.
<TextBox ref={register({ required: true })} label="Serial No" name="serialNo" />
const TextBox = React.forwardRef(({ label, name }, ref) => (
<>
<label htmlFor={name}>
{label} {***required*** && <span>*</span>}
</label>
<input type="text" name={name} id={name} ref={ref} />
</>
))
have a look at https://react-hook-form.com/api#useFormContext
import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
export default function App() {
const methods = useForm();
const onSubmit = data => console.log(data);
return (
<FormProvider {...methods} > // pass all methods into the context
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedInput />
<input type="submit" />
</form>
</FormProvider>
);
}
function NestedInput() {
const { register } = useFormContext(); // retrieve all hook methods
return <input name="test" ref={register} />;
}
which allow you to access all hook form methods in the nested component level.

My onChange function is not being passed down to child

I'm building a higher component where field input is grouped together with some other components. I'm trying to pass down my onChange function to the child component so it can change the state with the new input. all the other props are passed fine and I can see the using chrome dev tools, but even though I can see the onChange function if I console.log the props on the child, it is not present on the form control component which ultimately creates the input text field.
Here is the code, you can notice in the form render the FormGroup which is not using the higher InputFieldGroup component:
higher_component.js
import React from 'react'
import * as FormGroup from 'react-bootstrap/lib/FormGroup'
import * as ControlLabel from 'react-bootstrap/lib/ControlLabel'
import * as FormControl from 'react-bootstrap/lib/FormControl'
export const InputFieldGroup = (props) =>
<FormGroup
controlId={props.controlId}
validationState={props.validationState()}>
<ControlLabel>{props.controlLabel}</ControlLabel>
{console.log(props)} {/* I CAN SEE THE ONCHANGE FUNCTION HERE */}
<FormControl
type={props.type}
name={props.name}
value={props.value}
placeholder={props.placeholder}
onChange={props.handleChange}
/>
<FormControl.Feedback />
</FormGroup>
form.js
export default class RequestQuote extends Component {
...Some other class methods and stuff
handleTextChange = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return(
<form>
<InputFieldGroup
controlId='email'
validationState={this.emailValidationState}
controlLabel='email'
type='text'
name='email'
value={this.state.email}
placeholder='Enter Business Email'
onChange={this.handleTextChange}
/>
{/* When I don't use the higher component the onchange works fine */}
<FormGroup>
<ControlLabel>Name</ControlLabel>
<FormControl
type='text'
name='name'
value={this.state.name}
placeholder='Enter Name'
onChange={this.handleTextChange}
/>
<FormControl.Feedback />
</FormGroup>
</form>
)
}
}
Why isn't the onChange function being passed to the child input?
Because it is undefined! In fact you give
onChange={this.handleTextChange}
to the components as a props, if you want to call it do
props.onChange
and not
props.handleChange
otherwise, change the variable onChange={js} to handleChange={js}

React + Bootstrap + Redux value not working in form

I'm defining a form in React with Bootstrap and Redux with the following code:
import React from 'react';
import { FormGroup, ControlLabel, FormControl, HelpBlock, Button } from 'react-bootstrap';
import { connect } from 'react-redux';
import './actions';
const _c = component => connect(s => s)(component);
const FieldGroup = ({ id, label, help, ...props }) => {
return (
<FormGroup controlId={id}>
<ControlLabel>{label}</ControlLabel>
<FormControl {...props} />
{help && <HelpBlock>{help}</HelpBlock>}
</FormGroup>
);
};
const LoginForm = _c(React.createClass({
render() {
return (
<form>
<FieldGroup
id="loginText"
type="text"
label="Text"
placeholder="Email"
value={this.props.user.email ? this.props.user.email[0] : ''}
/>
<FieldGroup
id="loginPassword"
label="Password"
type="password"
/>
<Button bsStyle="primary" bsSize="large">Login</Button>
</form>
);
}
}));
This works, and the value appears in the "Username" field, but it's not editable. I tried changing value={this.props.user.email ? this.props.user.email[0] : ''} to defaultValue={this.props.user.email ? this.props.user.email[0] : ''} and that makes it editable, but the default value never appears. What am I doing wrong?
(I would comment but I don't have 50 rep yet)
Sounds like your initial value may be undefined. Can you console.log(this.props.user.email[0]) and see that value?

Resources