what is the use of {children} props of Layout - reactjs

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/>

Related

Passing values between components in React

I m beginner to reactJS and I m having so much trouble with self learning.
I want to print the data I get from first page.
I used 2 .js files
This is userpage.js:
import resultPage from "./resultPage";
// JS
//const input = document.getElementById('myText');
//const inputValue = input.value
// React
// value, onChange
const Multi = () => {
const [person, setPerson] = useState({ firstName: "", email: "", age: "" });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
//e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: "", email: "", age: "" });
resultPage(people, person);
}
};
return (
<>
<article className="form">
<form>
<div className="form-control">
<label htmlFor="firstName">Name : </label>
<input
type="text"
id="firstName"
name="firstName"
value={person.firstName}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="email">Email : </label>
<input
type="email"
id="email"
name="email"
value={person.email}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="age">Age : </label>
<input
type="number"
id="age"
name="age"
value={person.age}
onChange={handleChange}
/>
</div>
<button type="submit" className="btn" onClick={handleSubmit}>
add person
</button>
</form>
</article>
</>
);
};
export default Multi;
This has 2 textboxes and a submit button.
This code is from resultPage.js:
function resultPage(people, person) {
return (
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className="item">
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
);
}
export default resultPage;
What am I doing wrong? I m new to reactjs. So kindly spare my obvious mistakes and help me.
From React documentation
HTML form elements work a bit differently from other DOM elements in React, because form elements naturally keep some internal state.
You need to add handleSubmit to your form, and it'll work. As #Halcyon suggested, using a Capital case for a component is good. It's tough to distinguish between HTML elements and components if you use lowercase. Read this for more details.
I am attaching a working sandbox for your code.
You're calling resultPage in handleSubmit. That's not going to work. You want resultPage to be part of the rendering, probably conditionally.
Consider something like:
return <>
{person.firstName !== "" && <resultPage people={people} person={person} />}
{person.firstName === "" && <>
// the form
</>}
</>;
Also since resultPage is a component, it's best to capitalize it.
I think you probably want a 3rd component:
const MyComponent = () => {
const [ people, setPeople ] = React.useState([]);
const [ isEditing, setIsEditing ] = React.useState(false);
return <>
{isEditing && <Multi setPeople={(people) => {
setPeople(people);
setIsEditing(false);
}}
{isEditing === false && <resultPage people={people} />}
</>;
}
Mutli now accepts a prop setPeople that is called in handleSubmit.

ReactJS How to update the state in object which is in the array

Hello I have one problem that I don't know ho to solve.
I have simple formular where the user type som inputs. After that when he clicks on the Button the firstName, lastname and picture will be display under the formular. And when I click on the input it will show the address and date.
But I have problem to do that. In App.js I have a state which initialli si empty array and after click on submit button the user inputs is added to this empty array. In Suggestions.js I map the sugestions array for displaying every suggestion from the user.
In UserInputs.js I have a state where I add into state a 'visible' to false and I want to do, when I clicked on on suggestion in a list it will display the description and date below this particular sugestion.
I want to do it like this. In App.js
const detail = (suggestion) => {
setSuggestions([...suggestions]); //but I don't know how to set state for particular
suggestion in the array.
};
My code:
App.js
import React, { useState } from "react";
import Suggestions from "./components/Suggestions";
import UserInputs from "./components/UserInputs";
function App() {
const [suggestions, setSuggestions] = useState([]);
const addNewSuggestion = (suggestion) => {
setSuggestions([suggestion, ...suggestions]);
};
const detail = (suggestion) => {
setSuggestions([...suggestions]);
};
console.log("suggestions", suggestions);
return (
<div className="app-container">
<UserInputs addNewSuggestion={addNewSuggestion}></UserInputs>
<Suggestions suggestions={suggestions} detail={detail}></Suggestions>
</div>
);
}
export default App;
Suggestions.js
import React from "react";
export default function Suggestions({ suggestions, detail }) {
return (
<div className="suggestion-container">
<h1 className="suggestion-heading">Zoznam Podnetov</h1>
{suggestions.map((suggestion, index) => {
return (
<div
key={suggestion.id}
className="suggestion"
onClick={() => detail(suggestion)}
>
<div className="suggestion-number">{index + 1}</div>
<div className="suggestion-details">
<div className="suggestion-name">
{suggestion.firstName}
{` ${suggestion.lastName}`}
</div>
<div className="suggestion-address">{suggestion.address}</div>
{suggestion.visible ? (
<div className="suggestion-description">
<p>{suggestion.description}</p>
<p>Podnet bol pridaný: {suggestion.date}</p>
</div>
) : null}
</div>
<div className="suggestion-picture">
<img
src={suggestion.picture}
alt="obrázok"
className="suggestion-picture"
></img>
</div>
</div>
);
})}
</div>
);
}
Userinputs.js
import React, { useState } from "react";
export default function UserInputs({ addNewSuggestion }) {
const randomId = Math.floor(Math.random() * 1000000);
const [userInputs, setUserInputs] = useState({
id: randomId,
firstName: "",
lastName: "",
address: "",
description: "",
picture: null,
date: new Date().toLocaleDateString(),
visible: true,
});
const onInputChange = (event) => {
setUserInputs({
...userInputs,
[event.target.name]: event.target.value,
});
};
const fileSelectHandler = (event) => {
setUserInputs({
...userInputs,
picture: URL.createObjectURL(event.target.files[0]),
});
};
const onSubmit = (event) => {
event.preventDefault();
addNewSuggestion(userInputs);
setUserInputs({
id: randomId,
firstName: "",
lastName: "",
address: "",
description: "",
picture: null,
date: new Date().toLocaleDateString(),
visible: true,
});
};
return (
<div>
<form className="form-container">
<div className="row">
<label>Meno</label>
<input
autoFocus
type="text"
name="firstName"
value={userInputs.firstName}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Priezvisko</label>
<input
type="text"
name="lastName"
value={userInputs.lastName}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Adresa</label>
<input
type="text"
name="address"
value={userInputs.address}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Popis</label>
<input
type="text"
name="description"
value={userInputs.description}
onChange={onInputChange}
></input>
</div>
<div className="row">
<input type="file" onChange={fileSelectHandler}></input>
</div>
<button onClick={onSubmit} className="button">
Odoslať
</button>
</form>
</div>
);
}
Thank you very much for your help.
you can update the suggestion, where the id matches input suggestion and only update it. Please find the code below:
const detail = (suggestion) => {
let tempSuggestions = suggestions.map( (item) => {
if(item.id === suggestion.id) return suggestion
return item
})
setSuggestions([...tempSuggestions]);
}

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 set pre-field data in initial value of formik form in reactjs

I am creating a Formik form using map function in react js, but I also want to fill the initial data from the state. I am able to it in a static form via setting initial value like the following code
<Formik
initialValues={{
firstName: Data.firstName,
lastName: Data.lastName,
}}
validationSchema={SignupSchema}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log("inside form", values);
this.updateForm(values);
setSubmitting(false);
}, 400);
}}>
So, How can I do it if I am creating my input like the following code
const masterCategory = Object.keys(campaignObj.newMasterCategory).map(item => {
return (
<Field name={`master_category${fc}`} key={fc}>
{({ field }) => <input {...field} className="form-control nopadding-r input-width" type="text" placeholder="Enter Master Category" />}
</Field>
);
});
and rendering it like this
<div className={`col-6 ${this.state.retailflag}`}>
{masterCategory}
</div>
it works for me.
import React, { Component } from "react";
import { Formik, Field } from "formik";
export default class Form extends Component {
formlist = ["username", "password"];
render() {
return (
<Formik
initialValues={{ username: "", password: "" }}
onSubmit={this.props.handleSubmit}
{...this.props}
>
{formikProps => {
return (
<ul>
{this.formlist.map((item, i) => {
return (
<li key={i}>
<Field type="email" name={item} placeholder="Email" />
</li>
);
})}
<li>
<button type="submit" onClick={formikProps.handleSubmit}>
Login
</button>
</li>
</ul>
);
}}
</Formik>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Example => https://codesandbox.io/s/empty-monad-obfvx

React Formik + Yup, onChange touch the field

I would like to conditionally display errors in my form.
The way formik works is that if you change one field all validations are ran and all errors returned even thought you changed just one.
I would like to display the error only if the field was TOUCHED and I would like a field to be TOUCHED onChange. The first change to the field should make it touched.
At the moment formik is touching fields just on submit. How would I be able to touch it onChange?
This is my current form:
const optionsForSelect = (collection) => {
return collection.map(item => ({
value: item.id,
label: item.name
}))
}
const validationSchema = yup.object().shape({
length: yup
.number()
.min(1, 'Length should be a positive non-zero integer')
.required(),
frame_rate: yup
.string()
.required()
})
class SpecificationsForm extends React.PureComponent {
render() {
const {
values,
handleChange,
handleInputChange,
handleSelectChange,
handleBlur,
errors,
touched
} = this.props;
const debouncedHandleChange = debounce(handleChange, 200)
console.log(errors)
console.log('TOUCHED')
console.log(touched)
return (
<div className="panel panel-default specifications-panel" id="js-turbosquid-product-specifications-panel">
<div className="panel-heading">
<a href="#" className="js-more-info" data-toggle="collapse" data-target="#specifications-panel-instructions" tabIndex="-1">
Specifications
<i className="fa fa-question-circle" />
</a>
</div>
<div className="panel-body panel-collapse collapse in" id="specification-panel-body">
<div className="panel-body-container">
<div id="specifications-panel-instructions" className="panel-instructions collapse" />
<div className="row">
<div className="col-xs-6">
<PanelInputField
label='Length'
value={ values.length }
onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
formName='turbosquid_product_form_length'
fieldName='length'
/>
<div className="form-field-error">{errors.length ? errors.length : "No Error"}</div>
<PanelSelectField
label='Frame Rate'
value={ values.frame_rate }
onChange={ ({value}) => handleSelectChange('frame_rate', value) }
formName='turbosquid_product_form_frame_rate'
fieldName='frame_rate'
options={ optionsForSelect(frameRateDropdownData) }
searchable={ false }
clearable={ false }
/>
</div>
<div className="col-xs-6">
<PanelCheckBox
label='Biped'
checked={ values.biped }
onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
fieldName='biped'
formName='turbosquid_product_form_biped'
/>
<PanelCheckBox
label='Loopable'
checked={ values.loopable }
onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
fieldName='loopable'
formName='turbosquid_product_form_loopable'
/>
</div>
</div>
</div>
</div>
</div>
)
}
}
const ProductSpecificationsMotionCapturePanel = withFormik({
validationSchema,
enableReinitialize: true,
mapPropsToValues: (props) => (props),
handleInputChange: (props) => (props.handleInputChange),
handleSelectChange: (props) => (props.handleSelectChange),
})(SpecificationsForm)
export default ProductSpecificationsMotionCapturePanel
To touch a Formik field onChange, you can do this:
<Formik
initialValues={initialValues}
onSubmit={(values) => {
//submit form
}}>
{({ setFieldTouched, handleChange }) => {
return (
<Form>
<Field
name="type"
onChange={e => {
setFieldTouched('type');
handleChange(e);
}} />
</Form>
)
}}
Hi I think it's not doable onChange but you can do so when the input is blurred and you need to use the handleBlur function: onBlur={handleBlur}.
Also errors being an object you can display it only when a given [input name] has one.
Take a look at when validations are ran here in the docs: https://jaredpalmer.com/formik/docs/guides/validation#when-does-validation-run
A workaround would be to use formik's method getFieldMeta and pass your field's name and call the value prop which isn't null when you type something.
errorMessage={
formikProps.getFieldMeta("username").value
? formikProps.errors.username
: ""
}
It's possible to set the touched value without invoking validation again and one can do so by using the useFormik hook available in React 18+.
import { useFormik } from "formik";
const Component = () => {
const { setFieldTouched, handleChanged } = useFormik({
validateOnChange: true,
validateOnBlur: true,
validateOnMount: true,
});
const handleInput = (e) => {
setFieldTouched(e.target.name, true, false);
handleChanged && handleChanged(e);
};
return <input name="email" onInput={handleInput} />;
};

Resources