Next js send form data to parent page - reactjs

I create a simple page called lucky number
pages/lucky.js
import finder from '../../hooks/use-finder'
import NumberForm from '../components/number-form'
export default function LuckyNumber() {
const { data } = finder(number)
console.log(data)
return (
<>
<h1>Lucky Number</h1>
<NumberForm />
</>
)
}
export default function NumberForm() {
return (
<>
<form>
<label>
Number:
<input type="text" name="number" />
</label>
<input type="submit" value="Submit" />
</form>
</>
)
}
where NumberForm is a form where user can just input a number ex: 12345. Once use submits the form, I want to pass that number to my hook in the page finder(number) so I can check to see if that number is in my lucky list of numbers.
How can I pass the number that user submits to the page?

I think you can use parent state and send the setState to the child to update it i.e.
pages/lucky.js
import React, { useState } from 'react'
import finder from '../../hooks/use-finder'
import NumberForm from '../components/number-form'
export default function LuckyNumber() {
const [number, setnumber] = useState(0);
const { data } = finder(number)
console.log(data)
return (
<>
<h1>Lucky Number</h1>
<NumberForm onChange={setnumber} />
</>
)
}
export default function NumberForm({ onChange }) {
const [number, setnumber] = useState(0);
const handleChange = (event)=>{
setNumber(event?.target?.value)
}
const handleSubmit = (event)=>{
event.preventDefault();
onChange(number)
}
return (
<>
<form>
<label>
Number:
<input type="text" name="number" value={number} onChange={ handleChange } />
</label>
<input type="submit" value="Submit" onClick={ handleSubmit } />
</form>
</>
)
}

Related

Pass data of page1 to page2(on a differnet page when clicked on page1 on page1)

import React, { useState } from 'react';
function Page1() {
const [formData, setFormData] = useState({});
const handleChange = (event) => {
setFormData({
...formData,
[event.target.name]: event.target.value
});
}
const handleSubmit = (event) => {
event.preventDefault();
// update the state of Page2 to show the form data
window.Page2.setFormData(formData);
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" name="name" onChange={handleChange} />
</label>
<br />
<label>
Email:
<input type="email" name="email" onChange={handleChange} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
function Page2() {
const [formData, setFormData] = useState({});
// expose setFormData function to the global scope
window.Page2 = { setFormData };
return (
<div>
<p>Name: {formData.name}</p>
<p>Email: {formData.email}</p>
</div>
);
}
function App() {
return (
<div>
<Page1 />
<Page2 />
</div>
);
}
export default App;
This is my code in this using react-router-dom I want to show data of page2 on the next page when clicked on submit on page1.
How can I do that?
This is my code in this using react-router-dom I want to show data of page2 on the next page when clicked on submit on page1.
How can I do that?

React Form: fetching data entered by user

I'm working on a SignUp Form, I'm trying to fetch the data entered by the user but for some reason I'm getting just null values, like the next example:
So, for the task I'm using two components, Signup and Input, the bellow code is from Signup.js:
import React, { useContext, useState, useRef } from "react";
import Modal from "../UI/Modal";
import classes from "./Login.module.css";
import Input from "../UI/Input/Input";
const Signup = (props) => {
const firstnameInputRef = useRef();
const lastnameInputRef = useRef();
const emailInputRef = useRef();
const passwordInputRef = useRef();
const [isCanceling, setIsCanceling] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [didSave, setDidSave] = useState(false);
const [isErrorOnSave, setIsErrorOnSave] = useState(false);
//const cartCtx = useContext(CartContext);
const errorOnSignupHandler = () => {
setIsErrorOnSave(true);
};
const signupHandler = async (clientData) => {
setIsSaving(true);
const enteredFirstname = firstnameInputRef.current.value;
const enteredLastname = lastnameInputRef.current.value;
const enteredEmail = emailInputRef.current.value;
const enteredPassword = passwordInputRef.current.value;
const newClientData = {
firstname: enteredFirstname,
lastname: enteredLastname,
email: enteredEmail,
password: enteredPassword,
};
console.log(newClientData);
const response = await fetch("http://localhost:3000/clients", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newClientData),
});
if (!response.ok) {
errorOnSignupHandler();
} else {
setIsSaving(false);
setIsCanceling(false);
setDidSave(true);
//cartCtx.clearCart();
}
};
const isSavingModalContent = <p>Saving new user...</p>;
/* incluir transaccion para verificar si es exitoso o hubo algun error */
const errorOnSavingModalContent = (
<React.Fragment>
<p>The user account could not be created. Please try again later</p>
<div className={classes.actions}>
<button className={classes.button} onClick={props.onClose}>
Close
</button>
</div>
</React.Fragment>
);
const didSaveModalContent = (
<React.Fragment>
<p>User account created, welcome!</p>
<div className={classes.actions}>
<button className={classes.button} onClick={props.onClose}>
Close
</button>
</div>
</React.Fragment>
);
const SignupButtons = (
<React.Fragment>
<button className={classes["button--alt"]} onClick={signupHandler}>
Sign-Up
</button>
<button className={classes["button--alt"]} onClick={props.onClose}>
Close
</button>
</React.Fragment>
);
const modalActions = (
<div className={classes.actions}>{!isCanceling ? SignupButtons : ""}</div>
);
const SignupModalContent = (
<React.Fragment>
<Input
ref={firstnameInputRef}
id="firstname"
label="First Name"
type="text"
//isValid={emailIsValid}
//value={emailState.value}
//onChange={emailChangeHandler}
//onBlur={validateEmailHandler}
/>
<Input
ref={lastnameInputRef}
id="lastname"
label="Last Name"
type="text"
//isValid={emailIsValid}
//value={emailState.value}
//onChange={emailChangeHandler}
//onBlur={validateEmailHandler}
/>
<Input
ref={emailInputRef}
id="email"
label="E-Mail"
type="email"
autodata="off"
//isValid={emailIsValid}
//value={emailState.value}
//onChange={emailChangeHandler}
//onBlur={validateEmailHandler}
/>
<Input
ref={passwordInputRef}
id="paswword"
label="Password"
type="password"
autodata="new-password"
//isValid={passwordIsValid}
//value={passwordState.value}
//onChange={passwordChangeHandler}
//onBlur={validatePasswordHandler}
/>
<Input
//ref={passwordInputRef}
id="paswword2"
label="Confirm-Password"
type="password"
autodata="new-password"
//isValid={passwordIsValid}
//value={passwordState.value}
//onChange={passwordChangeHandler}
//onBlur={validatePasswordHandler}
/>
{modalActions}
</React.Fragment>
);
return (
<Modal onClose={props.onClose}>
{!isCanceling && !isSaving && !isErrorOnSave && !didSave && SignupModalContent}
{isSaving && isSavingModalContent}
{isErrorOnSave && errorOnSavingModalContent}
{!isSaving && didSave && didSaveModalContent}
</Modal>
);
};
export default Signup;
And this is the code from Input.js:
import React from 'react';
import classes from './Input.module.css';
const Input = React.forwardRef((props, ref) => {
return(
<div className={classes.input}>
<label htmlFor={props.input.id}>{props.label}</label>
<input ref={ref} {...props.input}/>
</div>
);
});
export default Input;
well, basically my question is what am I missing to the get the input data from the user?
Thanks a lot for your comments.
You generally shouldn't use refs the way you're using them.
Instead, have a state for each input, and have the input value equal to the state. When the input changes, update the state.
This way, the state always reflects the state of the form, and is synced up with it. It's a patter called "controlled components". See here for more details.
At a cursory look (without creating a sample app), it seems Input.js has an issue.
I have updated your component below:
import React from 'react';
import classes from './Input.module.css';
const Input = React.forwardRef((props, ref) => {
return(
<div className={classes.input}>
<label htmlFor={props.id}>{props.label}</label>
// It shouldn't be props.input
<input ref={ref} {...props}/>
</div>
);
});
export default Input;
I hope this fixes your issue, otherwise it would be a nice if you could create a sample app in codesandbox or another shareable place.

Get id from one form out of multiple forms? (React)

I am trying send only one of my form's id to my handleSubmit function in react. My forms are created via a map function, which creates a form for each data enter from my DB. My handleSubmit function currently take in an event and outputs it to the console log. When running the code, I get all of my id's instead of one. Any help?
Here is my code:
import React, { useRef, useState } from 'react';
export const Movie = ({listOfReviews}) =>{
const handleSubmit = (event) => {
console.log(event)
}
return (
<>
<h1>Your reviews:</h1>
{listOfReviews.map(review =>{
return(
<form onSubmit={handleSubmit(review.id)}>
<label>
Movieid:{review.movieid}
<input type="text" value={review.id} readonly="readonly" ></input>
<input type="text" value={review.comment}></input>
<input type="submit" value="Delete"></input>
</label>
</form>
)
})}
</>
)
}
You have a simple error in your onSubmit callback. Instead of calling handleSubmit in the callback prop, you should instead define an inline function that calls handleSubmit.
Like this:
<form onSubmit={() => handleSubmit(review.id)}>
Full code:
import React, { useRef, useState } from 'react';
export const Movie = ({ listOfReviews }) => {
const handleSubmit = (id) => {
console.log(id);
};
return (
<>
<h1>Your reviews:</h1>
{listOfReviews.map((review) => {
return (
<form onSubmit={() => handleSubmit(review.id)}>
<label>
Movieid:{review.movieid}
<input type="text" value={review.id} readonly="readonly"></input>
<input type="text" value={review.comment}></input>
<input type="submit" value="Delete"></input>
</label>
</form>
);
})}
</>
);
};

How to do validation using useRef()

How do I validate input box value using useRef .
Initial validation is not required once user clicks on input box and comes out then it should validate if input box is empty it should show input box cannot be empty.
Codesandbox Link
code i tried. using onBlur
export default function App() {
const name = React.useRef("");
const nameBlurData = (name) => {
console.log("name", name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
// show error message here
</form>
</div>
);
}
You can use "useRef" to validate the value of an input field.
No need to use "useState".
Below code is a basic implementation of OP's question
You can replace the "console.log" with your alert component.
import { useRef } from "react";
const ComponentA = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const onBlurHandler = (refInput) => {
if (refInput.current?.value === "") {
console.log(`${refInput.current.name} is empty!`);
}
}
return (
<form>
<input ref={emailRef} onBlur={onBlurHandler.bind(this, emailRef)} />
<input ref={passwordRef} onBlur={onBlurHandler.bind(this, passwordRef)} />
<form/>
)
}
Link to "useRef"
Note: Not tested, code typed directly to SO's RTE
You can use a local state and conditionally render an error message like this:
const [isValid, setIsValid] = useState(true)
const nameBlurData = (name) => {
setIsValid(!!name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
{!isValid && <span> input must not be empty </span> }
</form>
Note that you don't really need a ref in this case, you can just use the event object like:
onBlur={(event) => nameBlurData(event.target.value)}
You need to use useState hook to update the value of the name property. Using ref is not ideal here.
Live demo https://stackblitz.com/edit/react-apqj86?devtoolsheight=33&file=src/App.js
import React, { useState } from 'react';
export default function App() {
const [name, setName] = useState('');
const [hasError, setError] = useState(false);
const nameBlurData = () => {
if (name.trim() === '') {
setError(true);
return;
}
setError(false);
};
return (
<div className="App">
<form>
<input
onBlur={nameBlurData}
type="text"
value={name}
onChange={e => setName(e.target.value)}
placeholder="Enter First Name"
/>
{hasError ? <p style={{ color: 'red' }}>Name is required</p> : null}
</form>
</div>
);
}

Why does react turn my state into [object object]

I've got this straightforward component:
Here it is on CodeSandbox: https://codesandbox.io/s/fast-architecture-fgvwg?fontsize=14&hidenavigation=1&theme=dark
function Home() {
const [name, setName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(name);
};
return (
<>
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={setName}
type="text"
placeholder="name"
/>
<button type="submit">
submit
</button>
</form>
</>
);
}
export default Home;
As soon as I click in the input box, it turns into [object object] and I'd love to know why this is happening.
You are not passing a value to your name variable onChange. onChange returns event which you have to get the value from and set the name that way.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("");
const handleSubmit = e => {
e.preventDefault();
console.log(name);
};
return (
<>
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.currentTarget.value)} type="text" placeholder="name" />
<button type="submit">submit</button>
</form>
</>
);
}
The update here is the onChange attribute. You are grabbing the event e and setting the name to whatever that currentTarget value is.
onChange = { (e) => setName(e.currentTarget.value) }
Your onChange handler receives a change event object. If you want the new value you'll need to get it from the event: event.target.value:
<input
value={name}
onChange={e => setName(e.target.value)}
type="text"
placeholder="name"
/>
When you cast a value to a string, like when calling console.log, the value's toString method is invoked, which for objects returns [object Object] by default.
You had onChange set to setName. Setname is a function used to update the value of name.
You need to write a function to handle the name value being updating when the user types in a name. Set onChange equal to that function:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("");
const handleSubmit = e => {
e.preventDefault();
console.log(name);
};
function handleChange(e) {
e.preventDefault();
setName(e.target.value);
}
return (
<>
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={handleChange}
type="text"
placeholder="name"
/>
<button type="submit">submit</button>
</form>
</>
);
}

Resources