How to use React Router to pass data [duplicate] - javascript

This question already has answers here:
How to pass data from a page to another page using react router
(5 answers)
Closed last month.
I am trying to understand how to pass data using React Router in my situation of using a form. I am currently creating a workout app and one of my pages is a survey for the user to fill out. Once the user has filled this survey out the data would be passed on to a file called personalExercise.js. In this personalExercise file, I would use conditional rendering to determine where the user is best suited per their preference.
Description of the attempted action:
Step 1). The user would answer the questions in the survey (from the file question.js) and the answers would be submitted to the console.
Step2).
Once the questions are submitted the data would be passed on to a file(file called personalExercise.js), where conditional rendering would be used to send the user to a page set to their exercise type.
Ex. In question.js file a user selects:
Male
18-28
Stay Active
The data then is transferred to the file personalExercise.js
Where through a conditional statement, the user would be sent to a specific page.
Ex. if (gender === male && userAge === young && goals === loose weight) { return (page specified to user) }
This is an idea and I am trying to use react Router to perform this task. Google has been my friend and enemy during my research.
import React from 'react';
import Introduction from './components/introduction';
import Questions from './components/beginning';
import Male from './components/questions';
import {BrowserRouter as Router, Route, Routes} from 'react-router-dom';
export default function App() {
return (
<Router>
<Routes>
<Route path= "/" element={<Introduction />} />
<Route path="/beginning" element= {<Questions />} />
<Route path="/questions" element= {<Male />} />
</Routes>
</Router>
);
}
PersonalExercise
import React from 'react';
import {NavLink} from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.min.css'
//purpose: To have the user see their specific exercises.
function personalExercise(formData) {
}
// function workout(){
// }
Questions
import React, {useState} from 'react';
import 'bootstrap/dist/css/bootstrap.min.css'
import Form from 'react-bootstrap/Form';
export default function Questions() {
const[formData, setFormData] = useState({
gender: "",
userAge: "",
goals:"",
});
function handleChange(event) {
const { name, value, type, checked } = event.target;
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === 'checkbox' ? checked : value
};
});
}
function handleSubmit(event) {
event.preventDefault()
console.log(formData)
};
return (
<>
<header>Questions</header>
<Form onSubmit={handleSubmit}>
<fieldset>
<legend>What was your gender at birth</legend>
<input
type='radio'
id = 'male'
name = 'gender'
value = 'male'
checked={formData.gender === "male"}
onChange={handleChange}
/>
<label htmlFor="male"> Male </label>
<br />
<input
type='radio'
id='female'
name='gender'
value = 'female'
checked={formData.gender === "female"}
onChange={handleChange}
/>
<label htmlFor="female"> Female </label>
<br />
</fieldset>
<fieldset>
<legend>How old are you?</legend>
<input
type='radio'
id="young"
name="userAge"
value="young"
checked={formData.userAge === "young"}
onChange={handleChange}
/>
<label htmlFor="young"> 18-28 </label>
<br />
<input
type='radio'
id="middleAged"
name="userAge"
value="middleAged"
checked={formData.userAge === "middleAged"}
onChange={handleChange}
/>
<label htmlFor="middleAged"> 29-39 </label>
<br />
<input
type='radio'
id="older"
name="userAge"
value="older"
checked={formData.userAge === "older"}
onChange={handleChange}
/>
<label htmlFor="older"> 40-50 </label>
<br />
<input
type='radio'
id="senior"
name="userAge"
value="senior"
checked={formData.userAge === "senior"}
onChange={handleChange}
/>
<label htmlFor="senior"> 51+ </label>
<br />
</fieldset>
<br />
<fieldset>
<legend>What kind of fitness would you prefer?</legend>
<input
type="radio"
id="active"
name="goals"
value="active"
checked = {formData.goals === "active"}
onChange={handleChange}
/>
<label htmlFor='active'>To stay active!</label>
<br />
<input
type="radio"
id="weight"
name="goals"
value= "weight"
checked = {formData.goals === "weight"}
onChange={handleChange}
/>
<label htmlFor="weight"> To loose weight</label>
</fieldset>
<br />
<button type='submit'>Submit</button>
</Form>
</>
)
}

You can try passing in a function like this in App.js
export default function App() {
const [data, setData] = useState({})
const getData = (data) =>{
setData(data)
}
return (
<Router>
<Routes>
<Route path= "/" element={<Introduction />} />
<Route path="/beginning" element={<Questions getData={getData}/>} />
<Route path="/personalExercise" element={<personalExercise data={data}/>} />
<Route path="/questions" element= {<Male />} />
</Routes>
</Router>
);
}
Then in your questions.js you can use the function like this
export default function Questions(props) {
function handleSubmit(event) {
event.preventDefault()
props.getData(formData)
};
}
And to access the data in personalExercise.js you can call props.data like this
export default function personalExercise(props){
return (
<>
{props.data}//whatever you want to conditionally render
</>
);
}

Related

Having trouble getting my if/else statement to render to another component

I am having problems using my if/else statement in React.js. Currently I am trying to have my program use an if/else statement to render to another program using the useNavigate hook with React Router. I only have one statement to see if when the answers are selected they render to another component.
Test Case
Description. After filling in the user survey, when the user hits submit the user will be sent to a specific page dedicated to their specific health needs.
Step 1): The user fills in the questions form
Expectation: the user fills in the form and it is shown which answers the user selected.
Actual: The user fills in the form and you can see the answers selected.
Step 2): The user then hits submit, and then with the users answers the page is then rendered to another page dedicated for that users health.
Expectation: The user is rendered/taken to another page to look over there exercise options.
Actual: Nothing happens, or I get some sort of unexpected token error.
Errors Exceptions
I keep getting the error:
[Intervention] Slow network is detected. See https://www.chromestatus.com/feature/5636954674692096 for more details. Fallback font will be used while loading: chrome-extension://liecbddmkiiihnedobmlmillhodjkdmb/fonts/CircularXXWeb-Book.woff2, which I have tried restarting my computer but that didn't help any, would this affect my code?
In my code I tried using an if/else and a switch statement, that would explain the zombie code.
Here is my code:
import React, { useState } from 'react';
import Introduction from './components/introduction';
import Questions from './components/beginning';
import Male from './components/questions';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
export default function App() {
return (
//Revisit <Route path="/questions" element= {<Male />} /> for Readability!!
<Router>
<Routes>
<Route path= "/" element={<Introduction />} />
<Route path="/beginning" element= {<Questions />} />
<Route path="/personalExercise" element={<personalExercise/>} />
<Route path="/questions" element= {<Male />} />
</Routes>
</Router>
);
}
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />)
import React, { useState } from 'react';
import Form from 'react-bootstrap/Form';
import { useNavigate } from 'react-router-dom';
export default function Questions(props) {
const navigate = useNavigate()
const[formData, setFormData] = useState({
gender: "",
userAge: "",
goals:"",
});
function handleChange(event) {
const { name, value, type, checked } = event.target;
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === 'checkbox' ? checked : value
};
});
}
function handleSubmit(event) {
event.preventDefault()
navigate(getPath())
};
const getPath = () => {
if(formData.gender === "male" && formData.userAge === "Young" && formData.goals === "active"){
return navigate("/beginning")
}
// switch (formData) {
// case { gender: "male", userAge: "young", goals: "active" }: return navigate("../beginning");
// break;
// default:
// return navigate("/beginning")
// }
}
return (
<>
<header>Questions</header>
<Form onSubmit={handleSubmit}>
<fieldset>
<legend>What was your gender at birth</legend>
<input
type='radio'
id = 'male'
name = 'gender'
value = 'male'
checked={formData.gender === "male"}
onChange={handleChange}
/>
<label htmlFor="male"> Male </label>
<br />
<input
type='radio'
id='female'
name='gender'
value = 'female'
checked={formData.gender === "female"}
onChange={handleChange}
/>
<label htmlFor="female"> Female </label>
<br />
</fieldset>
<fieldset>
<legend>How old are you?</legend>
<input
type='radio'
id="young"
name="userAge"
value="young"
checked={formData.userAge === "young"}
onChange={handleChange}
/>
<label htmlFor="young"> 18-28 </label>
<br />
<input
type='radio'
id="middleAged"
name="userAge"
value="middleAged"
checked={formData.userAge === "middleAged"}
onChange={handleChange}
/>
<label htmlFor="middleAged"> 29-39 </label>
<br />
<input
type='radio'
id="older"
name="userAge"
value="older"
checked={formData.userAge === "older"}
onChange={handleChange}
/>
<label htmlFor="older"> 40-50 </label>
<br />
<input
type='radio'
id="senior"
name="userAge"
value="senior"
checked={formData.userAge === "senior"}
onChange={handleChange}
/>
<label htmlFor="senior"> 51+ </label>
<br />
</fieldset>
<br />
<fieldset>
<legend>What kind of fitness would you prefer?</legend>
<input
type="radio"
id="active"
name="goals"
value="active"
checked = {formData.goals === "active"}
onChange={handleChange}
/>
<label htmlFor='active'>To stay active!</label>
<br />
<input
type="radio"
id="weight"
name="goals"
value= "weight"
checked = {formData.goals === "weight"}
onChange={handleChange}
/>
<label htmlFor="weight"> To loose weight</label>
</fieldset>
<br />
<button>Submit</button>
</Form>
</>
)
}
import React from 'react';
import {NavLink} from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.min.css'
export default function beginning() {
return (
<>
<p>Before beginning, would you mind entering some info about yourself? This information
is used to help understand what kind of exercises suit you and lets the app know how
it can fit the 30 min sessions in your day!
</p>
<p>If you would like to skip the questionnaire and dive right into exercising, so you
can personally select what you want as your exercise, that is also an excellent
choice! </p>
<NavLink to="/questions">
<button>Take Questionnaire</button>
</NavLink>
<NavLink to="/exercise">
<button>Skip Questionnaire</button>
</NavLink>
</>
)
}
In your function getPath() you are returning the navigate function itself to navigate function. I think that is something which is triggering the error. Rather you can just call the getPath() function and remove the return keyword inside the if condition. If your condition is true it will navigate to the desired page or else nothing happens if the condition is not satisfied.
function handleSubmit(event) {
event.preventDefault()
getPath();
};
const getPath = () => {
if (formData.gender === "male" && formData.userAge === "Young" && formData.goals === "active") {
navigate("/beginning");
}
}

React setState hook keeps resetting and rendering the page twice

I have an react app Form component split into Login and Signup forms. It is supposed to render the Signup by default but switch to Login if login is button is clicked. When login button is clicked, the page switches to the Login form very briefly before switching back to the Signup form. I don't know what is causing this. I have tried placing const [page, setPage] = setState("signup") in the parent App and passing setPage as a prop along with page. This produced the same results. I believe this issue is similar to this one but that was not resolved.
Here is the app:
import Form from "./components/Signup-Form.js";
function App() {
return (
<div className="App">
<h1>Welcome</h1>
<Form />
</div>
);
}
export default App;
and Signup-Form.js:
import React from "react";
import { useState, useEffect } from "react";
import "./Forms.css";
import { InputField, Buttons } from "./Inputs";
function Form() {
const [page, setPage] = useState("signup");
const pageLabel = page;
let Signup = () => {
function toLogin() {
setPage("login");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company Name" id="comp-name" type="text" />
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Username" id="username" type="text" />
<InputField name="Email" id="email" type="email" />
<InputField name="Password" id="password" type="password" />
<InputField name="Confirm Password" id="confirm-password" type="password" />
</div>
<div className="btns">
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" />
<Buttons name="Log In" id="login-btn" type="button" cls="success" alt="true" onClick={toLogin} />
</div>
</form>
);
};
let Login = () => {
function toSignup() {
setPage("signup");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Password" id="password" type="password" />
</div>
<div className="btns">
<Buttons name="Log In" id="login-btn" type="submit" cls="success" />
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" alt onClick={toSignup} />
</div>
</form>
);
};
let form = (formType) => (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{formType}
</div>
</div>
);
if (page === "signup") {
const signup = Signup();
return form(signup);
} else if (page === "login") {
const login = Login();
return form(login);
}
}
export default Form;
The reason why after you click on Login button and get Login page and the page immediately re-renders and you get the Signup page is conditional render in your example. Right after clicking on Login button your state still previous and for this reason after click you get the main (Signup) page.
Suggest to change the structure render into smth like this:
...
return (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{page === "signup" && Signup()}
{page === "login" && Login()}
</div>
</div>
);
Here is the example in an action - https://codesandbox.io/s/smoosh-water-6jj18?file=/src/App.js

Redirect to Component onSubmit

My react app is not redirecting to the dashboard page after submitting a form. I tried using react-router-dom Redirect function but still with no success. I then opt-in for Browser History. push but still no success.
for the latter trial, the URL changes to /dashboard but the component remains on the form page, it doesn't move to dashboard until I reload the page
form field
<form>
<Input
displayValidationErrors={displayValidationErrors("fullname", validators)}
name="fullname"
type="text"
label="Full Name"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("password", validators)}
name="password"
type="password"
label="Password"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("password2", validators)}
name="password2"
type="password"
label="Confirm Password"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("email", validators)}
name="email"
type="email"
label="Email Address"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors(
"phone_number",
validators
)}
name="phone_number"
type="number"
label="Phone Number"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("card_number", validators)}
value={data.card_number}
name="card_number"
type="text"
label="Card Number"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("date", validators)}
value={data.date}
name="date"
type="text"
label="Expiry Date"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("pin", validators)}
name="pin"
type="password"
label="PIN"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<div className="col-lg-12 loginbttm">
<div className=" login-btm login-button">
<Button
handleClick={onSubmit}
type="submit"
className="btn btn-primary"
label="SUBMIT"
disabled={!isFormValid(validators)}
/>
</div>
</div>
</form>;
onSubmit function
const onSubmit = (e) => {
e.preventDefault();
browserHistory.push("/dashboard");
};
Button Component
const Button = ({ type, className, handleClick, label, disabled }) => (
<button
type={type}
className={className}
onClick={handleClick}
disabled={disabled}
>
{label}
</button>
);
My app.js
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/dashboard">
<Dashboard />
</Route>
<Route exact path="/">
<Form />
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
I don't see createBrowserHistory or something like <Router history={history}> so I guess you are using the default browser history. In that case you need withRouter to make it work:
import React from "react";
import { withRouter } from "react-router-dom";
function App() {
const onSubmit = (e) => {
e.preventDefault()
this.props.history.push("/personalInfo");
}
...
}
export default withRouter(App);
More about withRouter solution here
More about createBrowserHistory solution here
For functional component with react-router V5, you can also do with hooks:
import { useHistory } from "react-router-dom";
function App() {
let history = useHistory();
const onSubmit = (e) => {
e.preventDefault()
history.push('/dashboard');
}
return (
<Router>
<div className="App">
...
</div>
</Router>
);
}
Take a look at this to know more about useHistory
try using below. hope it'll help
this.props.history.push({
pathname: '/dashboard'
})
Another way of doing it with the function component -
import {withRouter} from "react-router-dom";
function SignIn({history}) {
const submit = (event) => {
event.preventDefault();
history.push("/profile");
}
....
}
export default withRouter(SignIn)

Show External Component On Checkbox Click Between Two Stateless Component

Am a bit new to react and redux. I am trying to call/show another stateless component's div from parent component. For example, if I have the below code
const funcA = ({key}) = > {
return (
<div>
<input type="checkbox">
</div>
);
};
export default funcA
const funcB = ({key}) = > {
return (
<React.Fragment>
<div>
<input type="text" placeholder="age" />
</div>
<div id="showThisDiv">
<input type="text" placeholder="age" />
</div>
</React.Fragment>
);
};
export default funcB
I am not trying go with classes. In Stateless components I know how to show/hide a section by using the useState, but I can only do this while in the same component. The issue or rather the challenge, is when I try to show/hide a section from another component. How would I show/hide the div with id showThisDiv in funcB when the checkbox is toggled in funcA?
It's possible using redux, but you also can do it using state and react hooks:
check out this codesandbox: https://codesandbox.io/s/vibrant-driscoll-odqmo
App.js
import React from "react";
import "./styles.css";
import FuncA from "./FuncA";
import FuncB from "./FuncB";
export default function App() {
const [age, setAge] = React.useState(0);
handleInput = (event) => {
console.log(event.target.value);
setAge(age === 0 ? 1 : 0);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<FuncA age={age} onChange={handleInput} />
<FuncB age={age} />
</div>
);
}
FuncA.js
import React from "react";
export default function FuncA(props) {
return (
<>
<label htmlFor="checkbox">
<input type="checkbox" name="age" onChange={props.onChange} value={props.age} />
</label>
</>
);
}
FuncB.js
import React from "react";
export default function FuncB(props) {
return (
<>
{props.age === 0 && <div className="divA">show div a</div>}
{props.age === 1 && <div className="divB">show div b</div>}
</>
);
}
Yeah, is something like this:
EDIT:
// ComponentA.js
const ComponentA = props => <input type="checkbox" onChange={props.onChange} />
// ComponentB.js
const ComponentB = props => (
<>
<div>
<input type="text" placeholder="age" />
</div>
{props.visible && (
<div id="showThisDiv">
<input type="text" placeholder="age" />
</div>
)}
</>
)
// App.js
const App = () => {
const [visible, setVisible] = useState(false);
return (
<>
<ComponentA onChange={() => setVisible(!visible)} />
<ComponentB visible={visible} />
</>
)
}
Now as you want..

Unable to call react component class from another component class [duplicate]

This question already has answers here:
onClick doesn't render new react component.
(5 answers)
Closed 6 years ago.
I am new to reactjs and javascript. I am trying to create a very basic login and registration form. When a client enters email and password, and clicks 'register', the form should take him to next form- which is Contact Information form. But my page refreshes and brings me back to original screen instead of contact information screen. Here's the code for login and contact info-
import React from 'react';
import {render} from 'react-dom';
import { ContactInfo } from './ContactInfo.jsx'
var App = React.createClass ({
handleClick: function(){
<ContactInfo new="new"/>;
},
render: function() {
return (<div>
<h1>Login</h1>
<form>
Email: <input type="text" name="email" method="get" />
<br />
<br />
Password: <input type="password" name="pwd" />
<br />
<i>forgot password?</i>
<br /><br />
<button>Login</button>
<button onClick={this.handleClick}>Register</button>
</form>
</div>);
}
});
render(<App />, document.getElementById('app'));
and Contact Info:
import React from 'react';
var ContactInfo = React.createClass({
render: function(){
return(
<div>
<form>
Name: <input type="text"/>
<br />
<br />
Phone: <input type="text"/>
<br />
Address:
Street <input type = "text" />
<br />
City <input type = "text" />
<br />
State <input type = "text" /><p> </p>zip <input type = "text" />
<br />
Country <input type = "text" />
<br /><br />
<button>Continue</button>
</form>
</div>);
}
});
export default ContactInfo;
Your handleClick method isn't behaving properly. right now it contains some jsx which is doing absolutely nothing.
What you should probably do is
Have a parent component that handles which view you're on
Login form and ContactInfo are each their own separate components
Parent keeps track of which form it should be rendering on its state
onClick should be updating that state, which will then cause the parent to re-render and update which form it is rendering
Sooooo
Something like this
React.createClass ({
getInitialState: function () {
return {
currentForm: "login"
};
},
handleLoginFormClick: function () {
this.setState({currentForm: "contact"});
},
renderLoginForm: function () {
return (
<LoginForm onClick={this.handleLoginFormClick} />
);
},
renderContactForm: function () {
return (
<ContactForm />
);
},
render: function () {
switch (this.state.currentForm) {
case "login":
return this.renderLoginForm();
case "contact":
return this.renderContactForm();
}
}
});

Categories