Send values from one browser tab to another in nextjs and populate formik form - reactjs

I have a form in next with a single input e.g. name on my page. On submit I would like the browser to open a new tab which contains a form with more inputs e.g. name, address, age. How can I pre-populate the name in the new tab?
I was considering the useContext hook but as far as I can tell that does not work across tabs. Do I need to use Redux at this point?
Edit: My attempt using localStorage so far:
// User inputs name which on submit is
// saved to local storage and /register page is opened
const Home: NextPage = () => {
return (
<Formik
initialValues={{ name: '' }}
onSubmit={(values) =>
localStorage.setItem('name', values.name)
}
>
{() => (
<Form>
<div>
<InputBox
type="text"
id="name"
name="name"
htmlFor="name"
label="Name"
placeholder=""
/>
<button
type="submit"
// ? Not sure using window is the correct way to do this in nextjs
onClick={(event) => window.open('/register', '_blank')}
>
Start KYC
</button>
</div>
</Form>
)}
</Formik>
)
import { Field, Form, Formik } from 'formik'
import { NextPage } from 'next'
import React from 'react'
const Register: NextPage = () => {
let nameInit = ''
React.useEffect(() => {
if (typeof window !== 'undefined') {
console.log('You are on the browser')
// 👉️ can use localStorage here
} else {
console.log('You are on the server')
// 👉️ can't use localStorage
}
nameInit = localStorage.getItem('name') ?? ''
console.log(nameInit)
}, [])
return (
<Formik
initialValues={{
name: nameInit,
}}
onSubmit={async (values) => {
console.log(values)
}}
>
{() => (
<Form className="space-y-8 divide-y divide-gray-200">
<div className="sm:col-span-2">
<label
htmlFor="name"
>
First name
</label>
<Field
type="text"
name="name"
id="name"
autoComplete="given-name"
/>
</div>
<div className="flex justify-end">
<button
type="submit"
>
Submit
</button>
</div>
</Form>
)}
</Formik>
)
}
Inspecting the page I can see that the value is being set and the console.log at the end of the useEffect also returns the expected value. But the form is still not being populated... My guess is the form is rendered before the useEffect is executed? When I just write the code in the function body instead of using useEffect it seems that is being executed on the server where localStorage is not available.

You're closer than you think! It works across tabs, but you might be using <link> or <a> tags to navigate.
If you use the built in next/link, your app won't refresh and useContext will work for you. Your app will also take advantage of Next JS's speed optimisations. Example:
import Link from "next/link"
const Nav = () => (
<Link href="gosomewhere">
<a>I'm a Link</a>
</Link>
)

Related

Formik Fetch API Values Undefined on submit

I am new to react and I need help with submitting my form with values that was obtained from an API.
When the form is loaded, the user has to input an ID in order for it to load the remaining field and values from the API. Once the User has inserted an ID value, the user can then click on submit and the in the back end it should POST the results capture in the Console log. Currently on submit input values are Undefined.
Visit CodeSandbox link below for a working example of this
Code: https://codesandbox.io/s/formik-fetch-post-3remet
Alternatively, here is my Code:
import React, { useState, useEffect } from "react";
import "./styles.css";
import { Box, Button, TextField } from "#mui/material";
import { Formik, Form } from "formik";
export default function App() {
const [datas, setdatas] = useState([]);
const [searchId, setSearchId] = useState("");
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/users/?id=${searchId}`)
.then((Response) => Response.json())
.then((datas) => setdatas(datas));
}, [searchId]);
const handleCange = (e) => {
setSearchId(e.target.value);
};
return (
<Formik
initialValues={{ name: datas.name }}
enableReinitialize={true}
onSubmit={(data, { resetForm }) => {
console.log(data);
resetForm();
}}
>
<div className="App">
<h1>Search User(enter a value between 1-5)</h1>
<div className="searchBox">
<input
type="text"
placeholder="Enter user ID"
onChange={(e) => handleCange(e)}
/>
</div>
<div className="itemsSec">
{datas.map((datas) => (
<div key={datas.id} className="items">
<Form>
<Box>
<TextField
className="field"
label="name"
name="name"
type="text"
id="name"
variant="filled"
value={datas.name}
onBlur={Formik.handleBlur}
onChange={Formik.handleChange}
sx={{ gridColumn: "span 2" }}
key={datas.id}
>
{" "}
value={datas.name}
</TextField>
</Box>
<Button type="submit" color="secondary" variant="contained">
Submit
</Button>
</Form>
</div>
))}
</div>
</div>
</Formik>
);
}

React - how to target value from a form with onClick

New to react and currently working on a project with a backend.
Everything functions correctly apart from targeting the value of user selection.
basically whenever a user enters a number the setId is saved properly to the const with no problems while using the onChange method.
this method would render my page every change on text.
I am trying to save the Id only when the user clicks the button. however,
event.target.value does not work with onClick.
I tried using event.currentTarget.value and this does not seem to work.
Code:
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input value={id} onChange={(e) => setId(e.target.value)} type="number" />
{/* <button value={id} type="button" onClick={(e) => setId(e.currentTarget.value)}>Search</button> */}
</form>
Handle Submit:
const handleSubmit = (e) => {
e.preventDefault();
console.log(id)
}
is there a way of doing this with onclick? since I wouldn't like my component to render on every typo and only once a user has clicked the button.
Componenet:
interface GetOneCompanyProps {
company: CompanyModel;
}
interface RouteParam {
id: any;
}
interface CompanyById extends RouteComponentProps<RouteParam> {
}
function GetOneCompany(): JSX.Element {
const [id, setId] = useState('4');
const [company, setCompany] = useState<any>('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(id)
}
async function send() {
try {
const response = await axios.get<CompanyModel>(globals.adminUrls.getOneCompany + id)
store.dispatch(oneCompanyAction(response.data));
console.log(response);
const company = response.data;
setCompany(company)
} catch (err) {
notify.error(err);
}
}
useEffect(() => {
send();
}, [id]);
return (
<div className="getOneCompany">
<h1>hi </h1>
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input value={id} onChange={(e) => setId(e.target.value)} type="number" />
{/* <button value={id} type="button" onClick={(e) => setId(e.currentTarget.value)}>Search</button> */}
</form>
<div className="top">
</div>
<br/>
Company: {id}
<br/>
Client Type: {company.clientType}
<br/>
Company Name: {company.name}
<br/>
Email Adress: {company.email}
<br/>
</div>
);
}
export default GetOneCompany;
Hope I am clear on this.
Thanks.
You can turn your input from being a controlled input to an uncontrolled input, and make use of the useRef hook. Basically, remove most of your attributes from the input element, and grab the current value of the input form on click of the button. From there, you can do whatever you want with the input value.
const inputRef = useRef()
...other code
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input type="number" ref={inputRef} />
<button value={id} type="button" onClick={() => console.log(inputRef.current.value)}>Search</button>
</form>
...other code
I'm afraid to say that here onChange is mandatory as we also are interested in the value which we set by setId. onClick can't be used as we can't set the value in the input.
Hope I'm clear.
Thankyou!

In React with Formik how can I build a search bar that will detect input value to render the buttons?

New to Formik and React I've built a search component that I'm having issues with the passing of the input value and rendering the buttons based on input length.
Given the component:
const SearchForm = ({ index, store }) => {
const [input, setInput] = useState('')
const [disable, setDisable] = useState(true)
const [query, setQuery] = useState(null)
const results = useLunr(query, index, store)
const renderResult = results.length > 0 || query !== null ? true : false
useEffect(() => {
if (input.length >= 3) setDisable(false)
console.log('input detected', input)
}, [input])
const onReset = e => {
setInput('')
setDisable(true)
}
return (
<>
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
setDisable(true)
setQuery(values.query)
setSubmitting(false)
}}
>
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
</div>
<div className="row">
<div className="col-12">
<div className="text-right">
<button type="submit" className="btn btn-primary mr-1" disabled={disable}>
Submit
</button>
<button
type="reset"
className="btn btn-primary"
value="Reset"
disabled={disable}
onClick={onReset}
>
<IoClose />
</button>
</div>
</div>
</div>
</Form>
</Formik>
{renderResult && <SearchResults query={query} posts={results} />}
</>
)
}
I've isolated where my issue is but having difficulty trying to resolve:
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
From within the Field's onChange and value are my problem. If I have everything as posted on submit the passed query doesn't exist. If I remove both and hard code a true for the submit button my query works.
Research
Custom change handlers with inputs inside Formik
Issue with values Formik
Why is OnChange not working when used in Formik?
In Formik how can I build a search bar that will detect input value to render the buttons?
You need to tap into the props that are available as part of the Formik component. Their docs show a simple example that is similar to what you'll need:
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
otherStuff()
}}
>
{formikProps => (
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
name="query"
onChange={formikProps.handleChange}
value={formikProps.values.query}
/>
</div>
<button
type="submit"
disabled={!formikProps.values.query}
>
Submit
</button>
<button
type="reset"
disabled={!formikProps.values.query}
onClick={formikProps.resetForm}
>
</Form>
{/* ... more stuff ... */}
)}
</Formik>
You use this render props pattern to pull formiks props out (I usually call them formikProps, but you can call them anything you want), which then has access to everything you need. Rather than having your input, setInput, disable, and setDisable variables, you can just reference what is in your formikProps. For example, if you want to disable the submit button, you can just say disable={!formikProps.values.query}, meaning if the query value in the form is an empty string, you can't submit the form.
As far as onChange, as long as you give a field the correct name as it corresponds to the property in your initialValues object, formikProps.handleChange will know how to properly update that value for you. Use formikProps.values.whatever for the value of the field, an your component will read those updates automatically. The combo of name, value, and onChange, all handled through formikProps, makes form handing easy.
Formik has tons of very useful prebuilt functionality to handle this for you. I recommend hanging out on their docs site and you'll see how little of your own code you have to write to handle these common form behaviors.

React: invoke props in a function

Fairly new to React so please let me know if I'm approaching this wrong.
In short, I want to be able to redirect to the login component after a form has been submitted in the signUp component.
When we click on a signUp or login button it changes the currentPage state to the assigned value. For example if currentPage is currently set to "Login" it will load the Login component and "Sign Up" with the Sign Up component. The components load as they should but when trying to pass in the props in the SignUp component I can't figure out how to invoke the pageSetter function after the form has been submitted.
I could just do the below, which works but I only want to invoke it in the onSubmit function
<form onSubmit={this.props.pageSetter}>
import React from "react";
function Button(props) {
return (
<button id={props.id} value={props.value} onClick={props.onClick}>
{props.value}
</button>
);
}
export default Button;
import SignUp from "./components/signUp.jsx";
import Login from "./components/login.jsx";
class App extends Component {
state = {
currentPage: "Login",
};
pageSetter = ({ target }) => {
this.setState({ currentPage: target.value });
};
render() {
return (
<div>
{this.state.currentPage !== "Sign Up" && (
<Button id={"signUp"} value={"Sign Up"} onClick={this.pageSetter} />
)}
{this.state.currentPage !== "Login" && (
<Button id={"login"} value={"Login"} onClick={this.pageSetter} />
)}
{this.state.currentPage === "Login" && <Login />}
{this.state.currentPage === "Sign Up" && (
<SignUp pageSetter={this.pageSetter} />
)}
</div>
);
}
}
export default App;
class SignUp extends Component {
myChangeHandler = (event) => {
let attribute = event.target.id;
let value = event.target.value;
this.setState({ [attribute]: value });
};
onSubmit = (event) => {
event.preventDefault();
this.props.pageSetter.value = "Login"
this.props.pageSetter
};
render() {
console.log(this.state);
return (
<div>
<form onSubmit={this.onSubmit}>
<p>real_name:</p>
<input id="real_name" type="text" onChange={this.myChangeHandler} />
<p>username:</p>
<input id="username" type="text" onChange={this.myChangeHandler} />
<p>email:</p>
<input id="email" type="text" onChange={this.myChangeHandler} />
<p>password:</p>
<input
id="password"
type="password"
onChange={this.myChangeHandler}
/>
<p>picture</p>
<input id="picture" type="text" onChange={this.myChangeHandler} />
<button id="userSubmit" type="submit">
Submit
</button>
</form>
</div>
);
}
}
export default SignUp;
I think there is a typo in your code example :
onSubmit = (event) => {
event.preventDefault();
this.props.pageSetter.value = "Login"
this.props.pageSetter
};
Could you please edit it and i'll check again if I can help !
Also, despite the typo, I don't understand why you try to set the property "value" on the props pageSetter which is a function.
I couldn't understand either why you're setting a property in a function. Instead of doing this, you should invoke the function using the value as argument.
this.props.pageSetter('Login');
You also should fix the pageSetter function to receive the page value instead of an event.

How to bind two methods simultaneously in reactjs

I have two components - one is App.js and other is Login.js and i have placed an input field and button in the Login and methods are placed in App.js. So i want to bind those methods by calling the Login component from the App.js.
Kindly review the logic in Login> tags as whenever i click on Flick button , it consoles the value for a second and then page refreshes automatically.
App.js
handleFlick(e){
console.log("Oho");
e.preventdefault()
}
handleChange(e) {
this.setState({
name: e.target.value
})
render() {
return (
<div>
<h1>{this.state.name} </h1><br></br>
<p>first component</p>
<Login
handleChange={this.handleChange.bind(this)}
handleFlick={this.handleFlick.bind(this)}
></Login>
Login.js
<div>
<form>
<input type="text" placeholder="enter name" onChange={(e) => { this.props.handleChange(e) }}></input>
<button onClick={(e) => { this.props.handleFlick(e) }}>Flick</button>
</form>
</div>
Change this:
<button onClick={(e) => { this.props.handleFlick(e) }}>Flick</button>
For this:
<button onClick={(e) => { this.props.handleFlick(e); e.preventDefault() }}>Flick</button>
type submit will by default refresh the page when sended

Resources