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.
Related
Below i have mentioned two code snippets one for Layout and another one of signup.here i used layout because i am going to use different layout for different pages. here my question is, what things of signup.js are taken by {children} props of Layout???
i am unclear about the use of children props, please give me clarifications
if some more clarification needed about code then please comment.
Layout.js
import React from "react";
import Menu from './Menu';
const Layout = ({ title = "Title", description = "Description",className="col-md-12",children}) => (
<div>
<Menu />
<div className="jumbotron">
<h2>{title}</h2>
<p className="lead">{description}</p>
</div>
<div className={className} >{children}</div> {/* without children in page there not show any form fields */}
</div>
);
export default Layout;
Signup.js
import React, { useState } from "react";
import { Link } from "react-router-dom"; //example of use in sign in link after signup
import Layout from "../core/Layout";
import { signup } from "../auth";
const Signup = () => {
const [values, setValues] = useState({
name: "",
email: "",
password: "",
error: "",
success: false,
});
const handleChange = (name) => (event) => {
setValues({ ...values, error: false, [name]: event.target.value }); //error false becoz when we donnot submit any thing and submit click it gives error but after type again
//error message disappear
};
const { name, email, password, success, error } = values;//to make thing easier we distructure here
const clickSubmit = (event) => {
event.preventDefault(); //when button clicked page going for reload we don't want so we use this
setValues({ ...values, error: false }); //when it is submitted we want set to previous error false
signup({ name, email, password }).then((data) => {
if (data.error) {
setValues({ ...values, error: data.error, success: false });
} else {
setValues({
...values,
name: "",
email: "",
password: "",
error: "",
success: true,
});
}
});
};
const signUpFrom = () => (
<form>
<div className="form-group">
<label className="text-muted">Name</label>
<input
onChange={handleChange("name")}
type="text"
className="form-control"
value={name} //when handle chenge happened handleChange method runs is update state what is the value of state that will be value of input field
/>
</div>
<div className="form-group">
<label className="text-muted">Email</label>
<input
onChange={handleChange("email")}
type="email"
className="form-control"
value={email}
/>
</div>
<div className="form-group">
<label className="text-muted">Password</label>
<input
onChange={handleChange("password")}
type="password"
className="form-control"
value={password}
/>
</div>
<button onClick={clickSubmit} className="btn btn-primary">
Submit
</button>
</form>
);
const showError = () => (
<div
className="alert alert-danger"
style={{ display: error ? "" : "none" }}
>
{error}
</div>
);
const showSuccess = () => (
<div
className="alert alert-info"
style={{ display: success ? "" : "none" }}
>
New account is created. please <Link to="/signin">Signin</Link>
</div>
);
return (
<Layout
title="Signup"
description="Sign up to Node React E-commerce App"
className="container col-md-8 offset-md-2"
>
{showSuccess()}
{showError()}
{signUpFrom()}
</Layout>
);
};
export default Signup;
Children prop is an array of components that is Layout's child
Example
<Layout>
<ComponentA />
<ComponentB />
<Layout/>
So the children prop will be an array like this [<ComponentA />,<ComponentB />]
When passing data to a component, there are two methods:
Pass data as props - this is used when you are passing known data types
Pass data as children - this is used when you need more flexibility
When you pass data as props, you can assign a custom name like this:
<Layout
title="Signup"
description="Sign up to Node React E-commerce App"
className="container col-md-8 offset-md-2"
/>
In the second method, everything within component is called children. In your case, showSuccess(), showError(), signUpFrom() are considered as children, and they will be rendered where you have the children inside <Layout/>
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
I'm building an edit button for my CRUD app. In this component, each individual 'rating' is mapped into one of these components. The component starts out be displaying the rating as stored in the DB, but users can press the edit button, and it turns into a form! (eventually, I'll get initial values to populate the form fields with the data displayed in the alternate render option).
Right now for the edit button, I have a custom submit handler receiving the submitted data from the two form fields as 'formProps'. However, before passing these off to the backend API, I ALSO need to figure out how to tie an id or something to the submit handler.
As seen in the component right below the form, this whole child component has access to the necessary passed down from the parent which can accessed as 'this.props.id'. Is there anyway to bundle 'this.props.id' with formProps before the handleSubmit takes it all to Redux Actions?
class Rating extends Component{
constructor(props){
super(props);
this.state = {
formClass: "notShowing",
ratingClass: "showing"
}
}
renderForm = () => {
this.state.formClass === "notShowing"
? this.setState({formClass: "showing", ratingClass: "notShowing"})
: this.setState({formClass: "notShowing", ratingClass: "showing"})
}
onSubmit = (formProps) => {
console.log("this is what the submitHandler recieves;", formProps);
this.props.editRating(formProps, () => {
this.props.history.push('/userDashboard');
});
}
render() {
const { handleSubmit, reset } = this.props;
return (
<div className="card darken-1" key={this.props._id}>
<div className={this.state.formClass}>
<form onSubmit={handleSubmit(this.onSubmit)}>
<p>What are you rating?</p>
<fieldset>
<Field
name="title"
type="text"
component="input"
autoComplete="none"
/>
<p>Add your rates!</p>
<Field
name="value"
type="number"
component="input"
autoComplete="none"
/>
</fieldset>
<button onClick={this.renderForm} type="submit" className="teal btn-flat right white-text">Submit</button>
</form>
<button onClick={this.renderForm}>Cancel</button>
</div>
<div className={this.state.ratingClass}>
<div className="card-content">
<span className="card-title">{this.props.title}</span>
<p>{this.props.value}</p>
<button onClick={this.renderForm}>Edit</button>
<button onClick={() => this.props.deleteRating(this.props.id)}>Delete</button>
</div >
</div>
</div>
);
}
}
function mapStateToProps({ratings}) {
return { ratings };
}
export default compose(
connect(mapStateToProps, actions),
reduxForm({ form: 'editRating' })
)(Rating);
You can use the third parameter of the handleSubmit function.
onSubmit = (values, _, props) => {
console.log(values, props.id);
...
}
...
const { handleSubmit, reset } = this.props;
<form onSubmit={handleSubmit(this.onSubmit)} .../>
Reference: https://redux-form.com/7.4.2/docs/api/reduxform.md/#-code-onsubmit-function-code-optional-
I have the following functional component
const input = props => (
<div>
<input placeholder="Type a message..." />
<div onClick={props.send} className="icon">
<i className="fa fa-play" />
</div>
</div>
)
How could I possibly pass the value of the input to props.send()?
I found a solution for this exact scenario on React's official docs: https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components
This approach allows your component to remain stateless and also doesn't require you to update the parent component on every change.
Basically,
const input = props => {
let textInput = React.createRef();
function handleClick() {
console.log(textInput.current.value);
}
return (
<div>
<input ref={textInput} placeholder="Type a message..." />
<div onClick={handleClick} className="icon">
<i className="fa fa-play" />
</div>
</div>
)
}
Edit May 2021: Since this answer seems to be getting some attention, I have updated the answer to use a hooks based approach as well, since that is what I would use now (If using React 16.8 and above).
const input = props => {
const [textInput, setTextInput] = React.useState('');
const handleClick = () => {
console.log(textInput);
props.send(textInput);
}
const handleChange = (event) => {
setTextInput(event.target.value);
}
return (
<div>
<input onChange={handleChange} placeholder="Type a message..." />
<div onClick={handleClick} className="icon">
<i className="fa fa-play" />
</div>
</div>
)
}
There are many ways to do it since you're very much concerned about performance. Here is the implementation, your component will be rendered only when you click on send button which actually means state will be updated once and input value will be displayed in parent component.
const Input = props => {
return (
<div>
<input onChange={props.changeHandler} placeholder="Type a message..." />
<button onClick={props.send}>send</button>
</div>
);
};
class App extends Component {
state = {
inputValue: ""
};
inputValue = '';
send = () => {
this.setState({ inputValue: this.inputValue });
};
changeHandler = event => {
this.inputValue = event.target.value;
};
render() {
console.log("In render");
return (
<React.Fragment>
<Input changeHandler={this.changeHandler} send={this.send} />
<div> {this.state.inputValue}</div>
</React.Fragment>
);
}
}
Since you mentioned that you just started with React, I'd suggest that you work through the documentation (which offers nice explanation).
According to your comment, the usage of a functional component is not a requirement. Therefore I'd recommend to do it that way -->
Your CustomInput component:
import React from "react";
import PropTypes from "prop-types";
class CustomInput extends React.Component {
constructor() {
super();
this.textInput = React.createRef();
}
static propTypes = {
send: PropTypes.func
};
render() {
const { send } = this.props;
return (
<React.Fragment>
<input placeholder="Type a message..." ref={this.textInput} />
<div
onClick={() => send(this.textInput.current.value)}
className="icon"
>
CLICK ME
</div>
</React.Fragment>
);
}
}
export default CustomInput;
If you noticed, I've replaced the empty div with React.Fragment. In that case you can omit the unnecessary <div> wrappings (if those are not required) which will keep your DOM clean (Read more about it here.
Usage:
<CustomInput
send={(prop) => {
console.log(prop)
}}
/>
I just used a dummy function which will log the input value to the console..
You can check the working example (Make sure to trigger the console in the editor) here
Posting this answer, If incase someone is using an earlier release of React 16.3. We can achieve the same thing by using callback refs instead without having to maintain state or having onChange event handler:
const input = props => (
<div>
<input ref={props.myRef} placeholder="Type a message..." />
<div onClick={props.send} className="icon">
<i className="fa fa-play" />
</div>
</div>
)
Calling that Input Component
handleClick = () => console.log(this.inputRef.value);
<Input myRef={el => this.inputRef = el} send={this.handleClick} />
I am new to react and am trying to get the value from the firstName input in handleSubmit. handleSubmit is working but for some reason the input value is undefined. I tried following some other examples but they were all forms in React components.
let SomeForm = (props) => {
let firstName = '';
const handleSubmit = (e) => {
e.preventDefault();
console.log(firstName);
}
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={firstName}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
SomeForm = connect()(SomeForm)
export default SomeForm
You need to add onChange to the TextField to handle the updates. And because SomeForm is a stateful component, you may need to use a class component instead of a stateless functional component.
class SomeForm extends React.Component {
state = {
firstName: ''
};
handleChange = (e, value) => {
this.setState({ firstName: value });
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.firstName);
};
render () {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TextField
id="text-field-controlled"
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={this.state.firstName}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
See the API and examples of TextField here: http://www.material-ui.com/#/components/text-field
You need function that you will throw in your TextField component and with onChange you can get value of input.
handleChange(e){
Console.log(e.target.value)
}
And in TextField
<TextField onChange={this.handleCahnge}/}
Or use refs
<TextField ref="textfield" />
And get value with this.refs.textfield.getValue()