Changing State of a Component by Input from children - javascript

I've got three forms - sign in, forgot password and sign up. Initial render is for a sign in component which has buttons for forget password or sign up. On click the buttons render their each respective component.
Where I am right now is that I have state assigned to each child component I want rendered and buttons changing the state in the parent component . I want to move these buttons to the child components so that I can change the state from there
Below is the sign in page and two of the three components I've mentioned.
export default function SigninPage() {
const [comp, setView] = useState('signin')
function toggleSignin(comp){
setView('signin')
}
function toggleReset(comp){
setView('reset')
}
function toggleSignup(comp){
setView('signup')
}
return (
<LoginStyles>
{comp ==='signin' &&(
<div>
<SignIn />
</div>
)
}
{comp ==='reset' &&(
<div><RequestReset/></div>
)
}
{comp ==='signup' &&(
<div><SignUp/></div>
)
}
<button onClick={toggleSignin}>Sign In</button>
<button onClick={toggleReset}>Forgot Password</button>
<button onClick={toggleSignup}>Sign Up</button>
</div>
);
}
export default function SignIn() {
return (
<Form>
<h2>Sign Into Your Account</h2>
<button type="submit">Sign In</button>
{/* onClick sets state to 'signup'*/}
<a>Create a New Account</a>
<a>Forgot Password</a>
</Form>
);
}
export default function RequestReset() {
return (
<Form >
{/* onClick sets state to 'signin'*/}
<a href='/signin'>**Go back**</a>
<h2>Request a Password Reset</h2>
<fieldset>
<label htmlFor='email'>
Email
</label>
<button type='submit'>Request Reset</button>
</fieldset>
</Form>
)
}

First off, I believe you should implement this behavior with routing, that approach you are using is definitely messy and hard to follow.
That said, I think the follow will do the trick:
<LoginStyles>
{items.map(({ id, component, isVisible }) => (
const Component = component;
<div key={id} hidden={!isVisible}>
<Component onClickComponent={() => handleClick(id)}
</div>
))}
</LoginStyles>
Of course you need to call onClickComponent later on in the childs, but you will have scope and keep the id.

Related

React Button Click should change the display value of div

I got a Navbar which has a button do change the display value of a login form. The Login form and the Login form is a diffrent file, the navbar is a diffrent file and the homepage where it should be display is a diffrent file. Those are the minimal variants of each so that you got some got to understand my problem in detail:
Homepage:
const HomePage = () => {
return (
<div>
<Navbar />
<Login />
<div id="content">
</div>
</div>
);
}
Navbar:
const Navbar= () => {
const showLogin = () => {
document.getElementById('Login').style.display='block';
}
return (
<div id="Navbar">
<NavLink activeClassName="active" to='/'><img src={logo}/></NavLink>
<ul>
...
</ul>
<ul>
<button onClick={showLogin}>Anmelden</button>
</ul>
</div>
);
}
Login-Form:
const Login = () => {
return (
<div id="Login">
<form>
<label>Anmelden</label>
<label for="username">Nutzername</label>
<input name="username" type="text"></input>
<label for="pw">Passwort</label>
<input name="pw" type="password"></input>
<button type="submit">Login</button>
</form>
</div>
);
}
Is there a way to achieve this, or would my easiest option be to include the Login source code into the Navbar source code?
You do not need to move your Login component inside Navbar. Keep it as it is.
You can use useState and Props to switch css classes to show/hide your Login component. I have created very simple solution for you in this CodeSandbox.
Steps:
Create two CSS classes hidden and block
In your Login component add a boolean prop which switches class hidden to block if true.
Create a prop for onClick in the Login component.
Create a useState inside your Homepage which holds a boolean value. That boolean value pass it to the Login page prop and then use onClick prop from Navbar to switch that boolean state
Yes, depending on your CSS system this is easily achievable just by using that.
The React solution is using refs.
The easy way is to create a ref in the parent component and then pass it down as a prop to both components:
In Homepage (i.e. parent), create a ref like so loginRef = useRef(); then pass it down as a prop to the 2 children.
In Login-Form.js you assign that prop on the div with id Login like so <div id='Login' ref={props.loginRef}>
Then in Navbar.js you can use that prop to change its display value like so const showLogin = () => {props.loginRef.current.style.display='block';}
NB: This is a fast and easy way, not best practice but it gets the work done. The best-practice here is to use forwardRef and - super advanced - useImperativeHandle. Take your time and go through the documentation when you're ready.
Login page will show "it is not active" first because active is set to false.but once you click on submit button it will show "it is active"
HomePage
const HomePage = () => {
const[active,setActive]=useState(false);
return (
<div>
<Navbar activesetter={setActive} />
<Login activestatus={active} />
<div id="content">
</div>
</div>
);
}
Login
const Login = (props) => {
return(
<div>
<div>
{props.activestatus ? "it is active" : "it is not active" }
</div>
</div>
);
}
Navbar
const Navbar = (props) => {
const handleSubmit=(e)=> {
e.preventDefault();
props.activesetter(true);
}
return(
<div>
<form onSubmit={handleSubmit}>
<button type="submit">Login</button>
</form>
</div>
);
}

useState redirecting to different component in Next.js

I'm using useState in Next.js to render different components based on which button the user clicks. Here's the main page's (called account.js in the app) code:
//getting components and importing react
import react from 'react'
const account = () => {
const [active, setActive] = react.useState("general")
return (
<>
<div className="container my-5">
<div className="container text-center mb-3">
<button onClick={() => setActive("general")} className="btn btn-primary btn-lg mx-3">General Information</button>
<button onClick={() => setActive("education")} className="btn btn-primary btn-lg mx-3">Education History</button>
<button onClick={() => setActive("tests")} className="btn btn-primary btn-lg mx-3">Test Scores</button>
<button onClick={() => setActive("background")} className="btn btn-primary btn-lg mx-3">Background information</button>
<button onClick={() => setActive("documents")} className="btn btn-primary btn-lg mx-3">Upload documents</button>
</div>
</div>
<div className="container my-5">
{
active === "zero" && <p className='text-center'>Select a field to start</p>
}
{
active === "general" && <General></General>
}
{
active === "education" && <Education></Education>
}
{
active === "tests" && <Tests></Tests>
}
{
active === "background" && <Background></Background>
}
{
active === "documents" && <Documents></Documents>
}
</div>
</>
)
}
export default account
Now one of these components, namely Education.js also has a button that when clicked, will show a different component, AddSchool.js. The problem is, when I use useState in Education.js, while it does show the component I want it to when the button is clicked, it redirects back to the first page (account.js) where I used useState.
Code for Education.js:
import AddSchool from './AddSchool.js'
import react from 'react'
const Education = () => {
const [schoolerActive, schoolActive] = react.useState("noSchool")
return (
<form action="">
{/* Some stuff here */}
<div>
<button onClick={() => schoolActive("schooler")} className='btn btn-warning'>Add Schools +</button>
{
schoolerActive === "noSchool" && <></>
}
{
schoolerActive === "schooler" && <AddSchool />
}
</div>
</form>
)
}
export default Education
I'm expecting that when I click the 'Add Schools +' button, it just renders the AddSchool.js component. What it does instead is renders the AddSchool.js component exactly like I want but then redirects to account.js for some reason.
Can someone point out what I'm getting wrong here?
A button without a type property in a form automatically submits the form causing the location of the page to change.
As the other answer mentioned, you need to add a type attribute to specify that a button is a button inside a form.
In HTML, if you put a button inside a form and there's no <input type="button" />, then that will automatically act as the submit button.
To fix this issue simply add type="button" to your button element; that way it won't submit the form unexpectedly.
<button type="submit" onClick={() => {...}}>...</button>

How do i pass data values to modals using react hooks?

I am working on using modals to accept form inputs on a react project
here is the plan component
plan/index.js
import React, { useState } from "react";
import Pay from '../Pay';
const Plan = () => {
const [payModal, setPayModal] = useState(false);
const [planMode, setPlanMode] = useState(true);
return (
<main class="main">
{payModal && <Pay setOpenPayModal={setPayModal} />}
<div class="plan">
<div>
<a class="plans" onClick={() => {setPayModal(true);}}>plan A</a>
<div class="plan">
<span class="plan">{!planMode ? "$19.99" : "$9.99"}</span>
<span class="plan">{!planMode ? "month" : "year"}</span>
</div>
</div>
<div>
<a class="plans" onClick={() => {setPayModal(true);}}>plan B</a>
<div class="plan">
<span class="plan">{!planMode ? "$29.99" : "$19.99"}</span>
<span class="plan">{!planMode ? "month" : "year"}</span>
</div>
</div>
</div>
</main>
);
};
export default Plan;
as you can see on the line {payModal && <Pay setOpenPayModal={setPayModal} />} where i call the pay modal component from the plan component and it opens up the modal
here is the pay component which is the modal component
pay/index.js
import React, { useState } from "react";
function Pay({ setOpenPayModal }) {
const [billingDetails, setBillingDetails] = useState({
price: "",
: "",
});
return (
<div class="modal">
<div class="modal">
<div class="close">
<button
onClick={() => {
setOpenPayModal(false);
}}
>
</button>
</div>
<div class="modal">
<form class="form" onSubmit={handleSubmit}>
<fieldset class="form">
<Field
label="Price"
id="price"
type="text"
value={billingDetails.price}
onChange={(e) => {
setBillingDetails({ ...billingDetails, price: e.target.value });
}}
/>
<Field
label="Frequency"
id="frequency"
type="text"
value={billingDetails.frequency}
onChange={(e) => {
setBillingDetails({ ...billingDetails, frequency: e.target.value });
}}
/>
</fieldset>
<button class="pay" onClick={handleSubmitPay}>
Pay
</button>
</form>
</div>
</div>
</div>
);
}
export default Pay;
The issue is I want to be able to pass the values price and frequency from the plan component to the pay modal component
for example for plan A is price="$19.99" and frequency="year", so based on the button clicked on the plan component page, those values get passed to the pay modal component in a dynamic way
how do I achieve this using react hooks?
You can use contexts to pass, but in this case I don't think it's the best option. What I really recommend is passing the state variable through the props.
{payModal && <Pay setOpenPayModal={setPayModal} price={price} frequency={frequency} />}
I usually use the Context (useContext) when I need values and various components, for example:
I need to save the user id that is logged in to various components, and instead of getting it from the server every time I need it, I keep it saved in my context that I created, so I can make the call only once.
Documentation-> https://pt-br.reactjs.org/docs/context.html

How to call a change a state in a component using a button function from another component In React?

Long story short; I have a button that involves a function and in that function I want to change the state (in this case a number) from another component that's taking the property from somewhere else.
So to me I made a stats component that takes in the value that I want to change and then the value is coming from the Table component and I want the button that I made that is coming from the Actions
component to change the state from the stats component. So instead of having the button in the Table Component (As seen below) I want to be able to run it from my Actions Component
Attached is the code that kinda works the way I want it but it doesn't look the way I want it (I want to invokve the change state function from the Actions column rather than inside the component where the state lives)
const Button = ({ handleClick, action, btnType }) => {
return (
<div>
<button class={btnType} onClick={handleClick}>
{action}
</button>
</div>
);
};
const Actions = ({ text, value, handleClick }) => {
return (
<td>
<button
type="button"
class="btn btn-primary"
data-toggle="modal"
id="exampleModal"
>
Launch demo modal
</button>
<Button btnType="btn btn-secondary" action="Attack" />{" "}
<Button btnType="btn btn-success" action="Travel" />{" "}
</td>
);
};
const Stats = ({ cash }) => {
return (
<td>
<ul>
<li>
{" "}
<span class="green">Cash: </span>
{cash}
</li>
<li>
<span class="red">HP: </span>100
</li>
<li>
<span class="blue">Energy: </span>100
</li>
</ul>
</td>
);
};
const Table = () => {
const [cash, setCash] = useState(300);
const sellAction = ({}) => {
setCash(cash - 1);
};
return (
<table>
<tr>
<th>Drugs</th>
<th>Quantity</th>
<th>Inventory</th>
<th>Stats</th>
<th>Actions</th>
</tr>
<TableItem />
<QuantItem />
<Inventory />
<Button
btnType="btn btn-danger"
handleClick={sellAction}
action="Sell"
/>{" "}
<Stats cash={cash} />
<Actions />
</table>
);
};
Pass setCash or sellAction function to Actions component as a prop. And then from Actions component, pass it to the Button component as a prop. Similar to what you did for cash.

Pass value of child component to parent component in React

Ok, working on my second ever React app. In this project, I am trying to use nested components (my last one just had 1 component). I've got a Button component that I am trying to render within the main App component, which is a calculator (Here is my design I am replicating in node/react locally: https://codepen.io/ryanmdoyle/pen/QBvjdw)
So far in my code, the only button I am actually implementing so far is the AC button. Everything else is copy/paste from my codepen design. I know some aspects like the CSS classes and values are getting passed around correctly because it displays the CSS properly, but I am trying to take the value of the Button component and use that within methods in the App component. Particularly in the handleInput method. I know with an input field you can get the event.target.value but that's obviously not working!
import React, { Component } from 'react';
// import './App.css';
const Button = (props) => <button id={props.id} className={props.class} value={props.value} onClick={this.handleInput}>{props.value}</button>
class App extends Component {
constructor(props) {
super(props);
this.state = {
resultDisplay: "",
entryDisplay: "",
}
this.handleInput = this.handleInput.bind(this);
}
handleInput(event) {
console.log(event.target.value);
this.setState({
entryDisplay: this.state.entryDisplay + event.target.value
})
}
render() {
return (
<div className="grid-container">
<div className="display">display</div>
<Button id="clear" class={`button button-secondary`} value="ac" />
<div id="plus-min" className="button button-secondary">+/-</div>
<div id="percent" className="button button-secondary">%</div>
<Button id="one" class="button button-primary" value={1} />
<div id="two" className="button button-primary">2</div>
<div id="three" className="button button-primary">3</div>
<div id="four" className="button button-primary">4</div>
<div id="five" className="button button-primary">5</div>
<div id="six" className="button button-primary">6</div>
<div id="seven" className="button button-primary">7</div>
<div id="eight" className="button button-primary">8</div>
<div id="nine" className="button button-primary">9</div>
<div id="zero" className="button-primary">0</div>
<div id="divide" className="button button-operator">/</div>
<div id="multiply" className="button button-operator">*</div>
<div id="subtract" className="button button-operator">-</div>
<div id="add" className="button button-operator">+</div>
<div id="decimal" className="button button-primary">.</div>
<div id="equals" className="button button-operator">=</div>
</div>
);
}
}
export default App;
const Button = (props) => <button id={props.id} className={props.class} value={props.value} onClick={this.handleInput}>{props.value}</button>
You are trying to add a function that is not local to Button.
For using it you need to pass the function like this
<Button id="clear" class={`button button-secondary`} value="ac" click={this.handleInput}/>
And when you try to use the function in Button use it like this
const Button = (props) => <button id={props.id} className={props.class} value={props.value} onClick={() => props.click()}>{props.value}</button>
One thing to remember this is null in a arrow function by default.
You must know that when ever you are trying to create a component where stateless or stateful doesnot matter its function set, variable must be separate. You cannot use it like you have tried in this case.
class in React is just like classes in other programming language almost.
Currently, in your Button component:
const Button = (props) => <button id={props.id} className={props.class} value={props.value} onClick={this.handleInput}>{props.value}</button>
this.handleInput isn't defined. It is defined in your App component but not in Button. If you try clicking the Button, you will get an error in the console.
What you're looking to do is pass a callback to your Button component from the App component via props:
In App:
<Button handleInput={this.handleInput} />
In Button:
<button onClick={props.handleInput}
Replace these line in your code
Button Component
const Button = (props) => <button id={props.id} className={props.class} value={props.value} onClick={props.onClick}>{props.value}</button>
Pass props in all button Component like this
<Button id="clear" class='button button-secondary' value="ac" onClick={this.handleInput}/>
Remember that you can pass entire functions as props to your components, which is the beauty of JavaScript and React! So, essentially, write the function to clear your screen in your main App component, and then pass a reference down to your button component. Attach the function to the onClick event for your button component.
// App.js
...
clearScreen() => this.setState({ resultDisplay: '', entryDisplay: ''})
...
<Button id="clear" class={`button button-secondary`} value="ac" onClick={clearScreen.bind(this)} />
// ButtonComponent.js
...
<button onClick={this.props.onClick} />
...
You will need to pass a function as a prop down to your child component, which will then allow you to alter the parent's functionality.
For example:
passFunction(value) {
// Modify passed parameter (value) from child and implement in parent
this.setState({value: value});
// or call that method that you want to call.
handleInput(value);
}
<Button passFunction={this.passFunction} ... />
Then in Button.js or wherever the child component is:
this.prop.passfunction(someValueToParent)

Categories

Resources