How to send input from one React component to other? - javascript

I want to create a login page. When the user submits the form, the username should be rendered on the dashboard. I am unable to figure that out.
import React from "react";
import Footer from "./Footer";
import Back from "./Back";
import { Link } from "react-router-dom";
const Login = () => {
return (
<div>
<Back />
<div>
<form className="login-form">
<h1 className="form-heading">Login</h1>
<input
className="form-input"
type="text"
placeholder="Enter your Username"
/>
<input
className="form-input"
type="password"
placeholder="Enter your password"
/>
<button className="form-button">
<Link to={"/dashboard"}>Login</Link>
</button>
</form>
</div>
<Footer />
</div>
);
};
export default Login;

To share data between two components, the standard react approach is to lift the state up to a parent component, then pass it down (through props or context). For example:
const App = () => {
const [user, setUser] = useState();
return (
<Routes>
<Route path="/login" element={<Login setUser={setUser}/>}
<Route path="/dashboard" element={<Dashboard user={user}/>}
</Routes>
)
}
const Login = ({ setUser }) => {
return (
// ...
<Link to="/dashboard" onClick={() => setUser('bob')}
// ...
);
}
const Dashboard = ({ user }) => {
return (
<div>
Hello {user}!
</div>
)
}

Related

React cannot preserv list between route changes

I have this little projekt where I enter some user info into a form and on submit it will display it on the same page in a table. This seem to work as intended but then when I click on Home page and then back to the form page the list is empty. I would like the list to persist as long as you browse the site.
I've been struggling with this for a while and would love to get some help.
I'll post the components.
import { useState } from "react";
import { Route, Routes } from "react-router-dom";
import Navbar from "./Components/Navbar";
import Home from "./Components/Home";
import PersonList from "./Components/PersonList";
import PersonDetails from "./Components/PersonDetails";
import LoginForm from "./Components/LoginForm";
import { UserContext } from "./Components/UserContext";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
function App() {
const [value, setValue] = useState(null);
return (
<div className="App">
<UserContext.Provider value={{value, setValue }}>
<Navbar />
<div className="content">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/PersonList" element={<PersonList />} />
<Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} />
<Route path="/LoginForm" element={<LoginForm />} />
</Routes>
</div>
</UserContext.Provider>
</div>
);
}
export default App;
import { Link } from "react-router-dom";
import { UserContext } from "./UserContext";
import { useContext, useState } from "react";
export default function Navbar() {
const {value, setValue} = useContext(UserContext);
return (
<nav className="navbar">
<h1>React Assignment</h1>
<div className="links">
<Link to="/">Home</Link>
<Link to="/PersonList">Person List</Link>
{ !value && <Link to="/LoginForm">Login</Link> }
{ value && <Link to={"/"} onClick={() => {setValue(null);}} >Logout</Link> }
{value}
</div>
</nav>
)
}
import { useState } from "react";
import UserForm from "./UserForm";
import UserList from "./UserList";
const PersonList = () => {
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState([]);
// update contact state.
const addContact = (contact) => {
updateContacts([...contacts, contact]);
};
return (
<div className="personlist">
<UserForm addContact={addContact} />
<UserList contacts={contacts} />
</div>
);
}
export default PersonList;
import { useState } from "react";
import { Form, Button } from "react-bootstrap";
// retrieve addContact function from PersonList.js as props.
export default function UserForm({ addContact }) {
// useState hook to manage state in functional components.
const [contactInfo, setContactInfo] = useState({
firstname: "",
lastname: "",
age: "",
nationality: "",
email: "",
});
// update input fields.
const handleChange = (event) => {
setContactInfo({ ...contactInfo, [event.target.name]: event.target.value });
};
// submit data to addContact function.
const handleSubmit = (event) => {
event.preventDefault();
addContact(contactInfo);
// clear input fields after submit
setContactInfo({
firstname: "",
lastname: "",
age: "",
nationality: "",
email: "",
});
};
return (
<div className="form-container w-50">
<Form onSubmit={handleSubmit}>
<h3>Contact Form</h3>
<Form.Control
size="sm"
type="text"
name="firstname"
placeholder="First Name"
required
value={contactInfo.firstname}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="text"
name="lastname"
required
placeholder="Last Name"
value={contactInfo.lastname}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="number"
name="age"
placeholder="Age"
value={contactInfo.age}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="text"
name="nationality"
placeholder="Nationality"
value={contactInfo.nationality}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="email"
name="email"
placeholder="Email"
required
value={contactInfo.email}
onChange={handleChange}
/>
<p></p>
<Button variant="primary" size="sm" type="submit">
Submit Contact
</Button>
<p></p>
</Form>
</div>
);
}
import { Table } from "react-bootstrap";
import uuid from "react-uuid";
import { Link } from "react-router-dom";
// retrieve contacts from PersonList.js as props
export default function UserList({ contacts }) {
if (contacts.length === 0) {
return <h5>The list is empty</h5>;
} else {
return (
<Table className="w-100" bordered hover size="sm">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Nationality</th>
<th>Email</th>
</tr>
</thead>
<tbody className="tablelinks">
{/* use .map to loop */}
{contacts.map((contact) => (
<tr key={uuid()}>
<td>
<Link to={`/Components/PersonDetails/${contact.firstname+contact.lastname}`}>
{contact.firstname}
</Link>
</td>
<td>{contact.lastname}</td>
<td>{contact.age}</td>
<td>{contact.nationality}</td>
<td>{contact.email}</td>
</tr>
))}
</tbody>
</Table>
);
}
}
If you are just needing to persist the contacts state so it is available when navigating to the "/PersonList" path then the obvious solution is to Lift State Up to a common ancestor component that remains mounted while routed components are mounted/unmounted. The App component is this ancestor.
function App() {
const [value, setValue] = useState(null);
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState([]);
// update contact state.
const addContact = (contact) => {
updateContacts(contacts => [...contacts, contact]);
};
return (
<div className="App">
<UserContext.Provider value={{value, setValue }}>
<Navbar />
<div className="content">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/PersonList" element={<PersonList {...{ addContact, contacts }} />} />
<Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} />
<Route path="/LoginForm" element={<LoginForm />} />
</Routes>
</div>
</UserContext.Provider>
</div>
);
}
...
const PersonList = ({ contacts, addContact }) => {
return (
<div className="personlist">
<UserForm addContact={addContact} />
<UserList contacts={contacts} />
</div>
);
}
Additionally if you need to also persist the contacts state when the page is reloaded/refreshed then you'll need to persist the state to something more long-term. Initialize/persist the state from/to localStorage.
Example:
function App() {
const [value, setValue] = useState(null);
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState(
JSON.parse(localStorage.getItem("contacts")) ?? []
);
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
...
}

Moving input values from one component on page to another component on another page in react

I am quite new to React and working on a project where I want to move the input values from a form from one page to be displayed on another after submiting the inputs.
I have the below Measurement component with the input fields:
import React, { useState } from "react";
import "./measurements.scss";
import images from "../constants/images";
import { GrCircleInformation } from "react-icons/gr";
import Tooltip from "./Tooltip";
import MeasurementData from "./MeasurementData";
const Measurements = () => {
const [toggleTooltip, setToggleTooltip] = useState(false);
const [weight, setWeight] = useState();
const [height, setHeight] = useState();
const [shoulder, setShoulder] = useState();
const [chest, setChest] = useState();
const [abdominals, setAbdominals] = useState();
const [hips, setHips] = useState();
const [thigh, setThigh] = useState();
const [calf, setCalf] = useState();
const handleSubmit = (e) => {
e.preventDefault();
};
return (
<div className="app__measurements">
<GrCircleInformation
fontSize={16}
onMouseEnter={() => setToggleTooltip(true)}
onMouseLeave={() => setToggleTooltip(false)}
/>
{toggleTooltip && (
<Tooltip text="All measurements should be carried out while muscles are relaxes and be done in the exact same areas of the body every time. The time of day when the measurements are carried out should also be consistent" />
)}
<h2 className="app__measurements-heading">MEASUREMENTS</h2>
<div className="app__measurements-data">
<form className="app__measurements-form" onSubmit={handleSubmit}>
<label htmlFor="weight">Weight (kg)</label>
<br />
<input
type="number"
id="weight"
value={weight}
onChange={(e) => setWeight(e.target.value)}
name="weight"
/>
<br />
<label htmlFor="height">Height (cm)</label>
<br />
<input
type="number"
id="height"
value={height}
onChange={(e) => setHeight(e.target.value)}
/>
<br />
<label htmlFor="shoulder">Shoulders</label>
<br />
<input
type="number"
id="shoulder"
value={shoulder}
onChange={(e) => setShoulder(e.target.value)}
/>
<br />
<label htmlFor="chest">Chest</label>
<br />
<input
type="number"
id="chest"
value={chest}
onChange={(e) => setChest(e.target.value)}
/>
<br />
<label htmlFor="abdominal">Abdominals</label>
<br />
<input
type="number"
id="abdominal"
value={abdominals}
onChange={(e) => setAbdominals(e.target.value)}
/>
<br />
<label htmlFor="hips">Hips</label>
<br />
<input
type="number"
id="hips"
value={hips}
onChange={(e) => setHips(e.target.value)}
/>
<br />
<label htmlFor="thigh">Thighs</label>
<br />
<input
type="number"
id="thigh"
value={thigh}
onChange={(e) => setThigh(e.target.value)}
/>
<br />
<label htmlFor="calf">Calves</label>
<br />
<input
type="number"
id="calf"
value={calf}
onChange={(e) => setCalf(e.target.value)}
/>
<button type="submit" className="app__measurements-btn">
SAVE RESULTS
</button>
</form>
</div>
<img src={images.success} alt="" />
</div>
);
};
export default Measurements;
I then have the next page where I want the inputs to appear after submitting:
import React from "react";
import FitnessHeader from "../components/FitnessHeader";
import "./userPage.scss";
const UserPage = () => {
return (
<>
<FitnessHeader />
<div className="app__user">
<div className="app__user-container">
<h1 className="app__user-heading">YOUR PROGRESS</h1>
<div className="app__user-content">
<div className="app__user-measurements-container">
<div className="app__user-section app__user-measurements">
<h2 className="app__user-subheading">LAST MEASUREMENTS</h2>
</div>
<div className="app__user-section app__user-bmr">
<h2 className="app__user-subheading">BMR RATINGS</h2>
</div>
<div className="app__user-section app__user-bmi">
<h2 className="app__user-subheading">BMI RATINGS</h2>
</div>
</div>
<div className="app__user-results">
<h2 className="app__user-subheading">PREVIOUS WORKOUT RESULTS</h2>
</div>
</div>
</div>
</div>
</>
);
};
export default UserPage;
These two pages are connected in the App file:
import React, { useState } from "react";
import "./App.scss";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Fitness from "./pages/Fitness";
import UserPage from "./pages/UserPage";
function App() {
return (
<>
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/fitness" element={<Fitness />} />
<Route exact path="/user" element={<UserPage />} />
</Routes>
</Router>
</>
);
}
export default App;
Unfortunately I don't really how to make these inputs appear on the UserPage.
Since you are not using any kind of state management or context,
you are supposed to lift up the state by bringing the children component closer to the nearest parent component in this case App.js.
Define all the states in the App.js component then pass the state value as props in the respective components like below
import {useState} from react
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Fitness from '...'
import UserPage from '....'
function app(){
const [weight, setWeight] = useState();
const [height, setHeight] = useState();
function submitData () =>{}
return (
<BrowserRouter >
<Routes>
<Route path='/' elements={<>home</>}
<Route path='/form' elements={<Fitness
setWeight={setWeight}
submitData={submitData}
/>}
<Route pat='/user' elements={<UserPage
weight={weight}
submitData={submitData}
/>}
</Routes>
</BrowserRouter >
)
}
in your components
export default function Fitness({ setWeight,submitData }){ use setWeight as required }
export default function UserPage({ weight }){ use weight as required }
you can read more about lifting up the state here
Props drilling here
I hope that helps.

Reactjs - Cant render functional component

I'm trying to render a functional component. But for some reason, I'm getting this sentence on the console You need to enable JavaScript to run this app.
This is App.js
import './App.css';
import Home from './components/pages/home/Home';
import SignUp from './components/pages/sign/SignUp';
import Checking from './components/pages/sign/Checking';
import Login from './components/pages/sign/Login';
import Summery from './components/pages/summery/Summery';
import UserList from './components/pages/users/Users';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UploadFiles from './components/pages/files/UploadFiles';
function App() {
return (
<Router>
<Routes>
<Route exact path='/' element= {<Home />}/>
<Route path='/sign-up' component= {Checking } />
<Route path='/log-in' element= {<Login />} />
<Route path='/admin' element= {<Summery />} />
<Route path='/users' element= {<UserList />} />
<Route path='/files' element= {<UploadFiles />} />
</Routes>
</Router>
);
}
export default App;
Home, Login, Summery, UserList and UploadFiles are React Components and not functions.
Only Checking is a function (Trying to convert everything to a function component).
They all render but only Checking logging into console You need to enable JavaScript to run this app.
This is Checking.js file
import React from "react";
import '../../../App.css';
import Button from '#material-ui/core/Button';
import SendIcon from '#material-ui/icons/Send';
import axios from 'axios';
import bcrypt from 'bcryptjs';
import Navbar from "../../navbar/Navbar";
import { useNavigate } from 'react-router-dom';
export default function Checking() {
const [companyID, setCompanyID] = React.useState('');
const [email, setEmail] = React.useState('');
const navigate = useNavigate();
function handleSubmit(Event) {
Event.preventDefault();
axios.post('/sign-up', {
companyID: companyID,
email: email})
.then(res =>{
//console.log(res.json());
console.log(res);
if(res.status === 200){
//this.app();
//history.push('/login');
}else if (res.status === 400){
console.log("duplicate ID");
}
}).catch(err =>{
// console.log("duplicate ID");
// console.log(err);
});
}
}
return (
<>
<Navbar />
<div className="register-container" ref={this.props.containerRef}>
<h1 className="sign-up">SIGN UP</h1>
<form onSubmit={handleSubmit}>
<div className="form">
<div className="form-group">
{/* <label htmlFor="company id">Company ID : </label> */}
<input
type="number"
name="companyID"
placeholder="Company id"
value={companyID}
onChange={(e) => setCompanyID(e.target.value)}
required/>
</div>
{ <div className="form-group">
{/* <label htmlFor="email">Email : </label> */}
<input
type="text"
name="email" placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required/>
</div> }
<div className="registerbtn">
{/* <button type="submit" class="btn btn-primary">Submit</button> */}
<Button type="submit" endIcon={<SendIcon />} color="primary" variant="contained">
Sign Up
</Button>
</div>
</div>
</form>
</div>
</>
);
}
What am I doing wrong?
Checking is also a react component and you need to render it like the others.
<Route path='/sign-up' element= {<Checking/> } />

I want to pass an image as a prop to another page

The main problem is that this image is selected from the file explorer and I am using react-router.
Add.js
this is where you select the image
import { Link } from "react-router-dom";
import About from "./About";
import './styles/modal.css'
import firebase from "firebase";
require("firebase/firestore")
require("firebase/storage")
export default function Add(props) {
const [image, setImage] = useState(null);
const [modal, setModal] = useState(false);
const pickImage = (event) => {
//console.log();
setImage(URL.createObjectURL(event.target.files[0]));
//console.log(image);
}
const toggle = () => {
setModal(!modal);
}
return (
<div>
<h1>Add</h1>
<button onClick={toggle}>Add image</button>
{modal ? (
<div className="modal-bg">
<div className="modal">
<img src={image} style={{ width: '60%', height: '60%' }} className="ex-img" />
<br /><br />
<label htmlFor="fie" className="gcoo btn-default">+ File
<input id="fie" type="file" onChange={pickImage} className="file-pick" />
</label>
<br />
<br />
<div className="bottom-buttons">
<Link to="/about">
<button className="save">Save</button>
</Link>
<button onClick={() => setModal(false)} className="closse">Close</button>
</div>
</div>
</div>
) : null}
</div>
)
}
I am using firebase but not in this file so you can ignore this.
MainRoutes.js
this is where all the routes and pages are.
import { Route } from "react-router";
import { Switch } from 'react-router-dom';
import ImageDisplay from "./components/ImageDisplay";
import Add from './components/Add';
export default function MainRoute(props) {
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay />} />
<Route exact path="/add" component={() => <Add />} />
</Switch>
);
}
finally this file ImageDisplay.js is where the image should be displayed
I dont have much on this file because i dont know how to put in any images.
I have tried props but whenever i imported the Imagedisplay it always showed the content on it and i dont want anything from image display. I only want to send an image over there.
import React from 'react'
import { Link } from "react-router-dom"
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img />
<p></p>
</div>
</div>
)
}
export default ImageDisplay;
Make sure that you are not reloading the page when moving between the two routes, since this will remove all state.
To share state between the two components you would need to store the state in the parent, and pass it to the children.
Add:
export default function Add(props) {
const pickImage = (event) => {
props.setImage(URL.createObjectURL(event.target.files[0]));
}
// The rest of your function
}
And in your parent:
export default function MainRoute(props) {
const [image, setImage] = useState(null)
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay image={image} />} />
<Route exact path="/add" component={() => <Add setImage={setImage} />} />
</Switch>
);
}
You can now access the image prop in your imageDisplay.
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img src={props.image} />
<p></p>
</div>
</div>
)
}

React router navbar navigation

Im new to react and im having issues with the routing. I want the navbar to render on some pages but not others.What is the correct way to do this? I know im not supposed to render it in specific components.
so if this is my app.js
var App = React.createClass ({
render (){
return (
<div>
<NavbarInstance />
</div>
);
}
});
document.write('<div id="container"></div>');
ReactDom.render(
<Router history={createHistory({ queryKey: false })}
onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" component={App} />
<Route path="/login" component={LoginForm} />
<Route path="/other" component={Other} />
</Router>,
document.getElementById('container')
);
and this is my login page(see navbar instance-incorrect)
import React from 'react';
import Input from 'react-bootstrap/lib/Input';
import NavbarInstance from './components/header.jsx';
const LoginForm = React.createClass({
getInitialState: function() {
return {
username:'',
password:''
}
},
render () {
return (
<div>
<NavbarInstance />
<div className = "col-sm-12">
<h3> Log In </h3>
</div>
<div className ="col-sm-6">
<Input type = "text"
placeholder ="Username"
/>
<Input type= "password"
placeholder="Password"
/>
</div>
</div>
)
}
})
export default LoginForm
One option would be to keep track of what page you are in within a state variable within your main App component. Then add a check (say you didn't want to render it if page is 'index'.
return (
{ if (this.state.page !== 'index')
return <NavbarInstance />
}
)

Categories