Using input state in different components - reactjs

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

Related

Programmatically control the properties of a component

Suppose I have a component that a parameter from another component called jobData. The component could be a value or be undefined. If it has a value, I want to assign it to a textField property called defaultValue. If jobData is undefined, I want to assign it to something else. I tried the below in my code, but it didn't work. Is there any/another way to do this?
import React from 'react'
import {Dialog, TextField} from '#mui/material'
export default function myFunction({jobData}) {
return(
<div>
<form>
<TextField
autoFocus
margin="dense"
width="100%"
id="my_id"
label="My ID"
type="text"
name="myID"
defaultValue={if({jobData.length} > 0){
{jobData[0]['id']}
} else { {jobData.length.toString()}
}
/>
</form>
</div>
)
Try using encapsulation
import React from 'react'
import {Dialog, TextField} from '#mui/material'
export default function myFunction({jobData}) {
function isJobDataUndefined(){
if(jobData.length > 0){
return jobdata[0]['id']
}
return jobData.length.toString()
}
return(
<div>
<form>
<TextField
autoFocus
margin="dense"
width="100%"
id="my_id"
label="My ID"
type="text"
name="myID"
defaultValue={isJobDataUndefined()}
/>
</form>
</div>
)

Blank white screen on localhost:3000 in my react project

I am getting blank white screen on localhost:3000 in my React project. The components dont get rendered. I guess the issue is with one component, because when i comment out that component(SearchForm.js) from JSX, the other components do show up. Kindly highlight what could be the possiblities causing the issue. Thanks
SearchForm.js
import { Form, Col } from 'react-bootstrap'
export default function SearchForm({ params, onParamChange }) {
return (
<Form className="mb-4">
<Form.Row className="align-items-end">
<Form.Group as={Col}>
<Form.Label>Description</Form.Label>
<Form.Control onChange={onParamChange} value={params.description} name="description" type="text" />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Location</Form.Label>
<Form.Control onChange={onParamChange} value={params.location} name="location" type="text" />
</Form.Group>
<Form.Group as={Col} xs="auto" className="ml-2">
<Form.Check onChange={onParamChange} value={params.full_time} name="full_time" id="full-time" label="Only Full Time" type="checkbox" className="mb-2" />
</Form.Group>
</Form.Row>
</Form>
)
}
App.js
import React, { useState } from 'react';
import useFetchJobs from './useFetchJobs'
import { Container } from 'react-bootstrap'
import Job from './Job'
import JobsPagination from './JobsPagination';
import SearchForm from './SearchForm';
function App() {
const [params, setParams] = useState({})
const [page, setPage] = useState(1)
const { jobs, loading, error, hasNextPage } = useFetchJobs(params, page)
function handleParamChange(e) {
const param = e.target.name
const value = e.target.value
setPage(1)
setParams(prevParams => {
return { ...prevParams, [param]: value }
})
}
return (
<Container className="my-4">
<h1 className="mb-4">GitHub Jobs</h1>
<SearchForm params={params} onParamChange={handleParamChange} />
<JobsPagination page={page} setPage={setPage} hasNextPage={hasNextPage} />
{loading && <h1>Loading...</h1>}
{error && <h1>Error. Try Refreshing.</h1>}
{jobs.map(job => {
return <Job key={job.id} job={job} />
})}
<JobsPagination page={page} setPage={setPage} hasNextPage={hasNextPage} />
</Container>
)
}
export default App;
This seems okay, will need more information, Like how did you import and use it in another file.
After trying it out, I decided to just import { Row } directly from react-bootstrap.
But if you would like to continue with Form.Row, try checking how you imported bootstrap in index.js
import "bootstrap/dist/css/bootstrap.css";

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop when using useState()

App.js:
import React, { useState } from "react";
import Login from "./Login";
function App() {
const [id, setId] = useState();
return (
<>
{id}
<Login onSubmit={setId()}/>
</>
);
}
export default App;
and
Login.js:
import React, { useRef } from 'react'
import { Container, Form, Button } from "react-bootstrap";
export default function Login({ onIdSubmit }) {
const idRef = useRef();
function handleSubmit(e) {
e.preventDefault()
onIdSubmit(idRef.current.value)
}
return (
<Container className="align-items-center d-flex" style={{height: "100vh"}}>
<Form className="w-100" onSubmit={handleSubmit}>
<Form.Group>
<Form.Label>
Enter your Id
</Form.Label>
<Form.Control type="text" ref={idRef} required/>
</Form.Group>
<Button type="submit" style={{marginRight: "5px", marginTop: "5px"}}>Login</Button>
<Button variant="secondary" style={{marginTop: "5px"}}>Create A New Id</Button>
</Form>
</Container>
)
}
It appears that the error is in the App.js on the onSubmit={setId()} because when I comment it out it works.
The idea here is that when you click the "Login" button the value in the <Form.Control type="text" ref={idRef} required/> is stored in the useState from the App.js. Can I do this without getting the Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.?
Just use setId without parenthesis (). When you write the parenthesis beside a function, it means you are actually calling the function, which is causing rerenders. But in your case, you just want to pass the reference of your function to your Child Component.
<Login onIdSubmit={setId}/>
And also rename onSubmit to onIdSubmit as #Vaibhav commented.

react-hook-form Controller issues

Hi im trying to do one form with react-hook-form and material-ui. I don't want to write Controller every time for all TextFields. Because of that i declare it in another file and call it in my form but its not working i didn't understand why, because in some videos that i watched is working. What is the problem and how i can fix it ?
Form Field
import React from 'react'
import { TextField, Grid } from '#material-ui/core'
import { useForm, Controller, useFormContext } from 'react-hook-form'
const FormField = ({name, label}) => {
const { control } = useForm()
return (
<Grid item xs={12} sm={6} >
<Controller
render = {({field}) =>
<TextField
{...field}
label={label} required
/>}
name={name}
control = {control}
defaultValue=""
/>
</Grid>
)
}
export default FormField
Adress Form
import React from 'react'
import { InputLabel, Select, MenuItem, Button, Grid, Typography, TextField } from '#material-ui/core'
import { useForm, FormProvider, Controller } from 'react-hook-form'
import FormField from './FormField'
import { Link } from 'react-router-dom'
const AdressForm = ({next}) => {
const {handleSubmit, control} = useForm()
return (
<>
<Typography variant="h6" gutterBottom>Shipping Address </Typography>
<form onSubmit={handleSubmit((data) => console.log(data) )}>
<Grid container spacing={3}>
<FormField name='firstName' label='First Name' required='required'/>
<FormField name='lastName' label='Last Name' />
<FormField name='email' label='Email' />
<FormField name='phoneNumber' label='Phone Number' />
</Grid>
<br/>
<div style={{ display: 'flex', justifyContent: 'space-between'}}>
<Button component={Link} to="/cart" variant="outlined">Back to Cart</Button>
<Button type="submit" variant="contained" color="primary">Next</Button>
</div>
</form>
</>
)
}
export default AdressForm
You must use one useForm hook for each form, in your code, you call useForm in every Field components, creating multiple independent form states, which leads to unexpected result.
What you need to do is to call useForm in the parent element and pass the dependencies (register, formState, error...) down the child components, so your form can have one unified state. If you have a deeply nested components, you can use useFormContext to pass the form context to the nested children easily:
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 {...register("test")} />;
}

How to handle submitted values in my form using redux-form and serverside validation?

I'm using redux-form with a login form component in ReactJS.
But when I pass values to my form and I click on the submit button the values returned by the console.log are empty, and I don't know how to debug that.
Here's my form component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';
import {reduxForm, Field} from 'redux-form';
import classnames from 'classnames'
// Actions
import {signin} from '../../actions/auth';
// Bootstrap
import { Grid, Row, Col, Image } from 'react-bootstrap';
// Includes
import '../../assets/css/users/signin.min.css';
import logo from '../../assets/images/datazonia_icone.png';
const renderField = ({input, label, type, forgotPassword=false, meta: {touched, error}}) =>(
<div className="form-group">
<label>{label}</label>
<input {...input} type={type}/>
{forgotPassword &&
<span className="forgot-pw">
<Link to="/users/password/reset">mot de passe oubliƩ ?</Link>
</span>}
{touched &&
error &&
<span className="help-block">
{error}
</span>}
</div>);
let SigninForm = (props) => {
const {handleSubmit, submitting, error } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name="login"
component={renderField}
type='text'
input={{
className: "form-control"
}}
label="Email ou nom d'utilisateur"
/>
<Field
name="password"
component={renderField}
type="password"
input={{
className: "form-control"
}}
label='Mot de passe'
forgotPassword
/>
{error &&
<strong>
{error}
</strong>}
<button disabled={submitting} type="submit" className="btn btn-block btn-datazonia">Connexion</button>
</form>
);
};
SigninForm = reduxForm({
form: 'signin'
})(SigninForm);
class UserSignin extends Component {
onSubmit = (values) => {
console.log(values);
return this.props.signin(values, this.props.history, 'users');
};
render() {
return (
<div className="UserSignin">
<Grid>
<Row className="show-grid bloc-sign">
<Col sm={4} smOffset={4} xs={12} className="text-center title">
<Link to="/">
<Image src={logo} responsive className="center-block"/>
</Link>
<h3>Se connecter</h3>
</Col>
<Col sm={4} smOffset={4} xs={12}>
<div className="signin-form">
<SigninForm onSubmit={this.onSubmit}/>
</div>
</Col>
</Row>
</Grid>
</div>
);
}
}
UserSignin = connect(null, {signin})(withRouter(UserSignin));
export default UserSignin;
My values are empty when i click on the submit button, how can i get it to work ?
(And sorry for my English, I'm French)
OK, I've resolved this issue.
the problem was
input={{
className: "form-control"
}}
overrides the default behavior of redux-form

Resources