I am wondering which way of calling mutiple components is better. Here we have example one which calls components in a composition type way another word for this would be (High-order functions???)
var App = React.createClass({
render:function () {
return(
<div>
<div className="container">
{this.props.children}
</div>
</div>
)
}
});
// Title Component
var Title = React.createClass({
render:function () {
return(
<App>
<div className="text-center">
<h1>Rock App</h1>
<h4>An Easy Way To Track Your Rock Climbing Progress</h4>
</div>
{this.props.children}
</App>
)
}
});
// Login Component
var Login = React.createClass({
render:function () {
return(
<Title>
<div>
<form className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">Email</label>
<div className="col-sm-10">
<input type="email" className="form-control" id="inputEmail3" placeholder="Email"/>
</div>
</div>
<div className="form-group">
<label className="col-sm-2 control-label">Password</label>
<div className="col-sm-10">
<input type="password" className="form-control" id="inputPassword3" placeholder="Password"/>
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button type="submit" className="btn btn-default">Sign in</button>
</div>
</div>
</form>
</div>
</Title>
)
}
});
ReactDOM.render(<Login/>, document.getElementById('app'));
Here you would call Login, which is within Title which is within App.
Another way is to create each component separately and have a main parent component which calls each sub-component children attributes like so...
var Title = React.createClass({
render: function () {
return(
<div className="head text-center">
<h1>Rock App</h1>
<h3>The only app you need to track your climbs</h3>
</div>
)
}
});
var Login = React.createClass({
render: function () {
return(
<div>
<form className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">Email</label>
<div className="col-sm-10">
<input type="email" className="form-control" id="inputEmail3" placeholder="Email"/>
</div>
</div>
<div className="form-group">
<label className="col-sm-2 control-label">Password</label>
<div className="col-sm-10">
<input type="password" className="form-control" id="inputPassword3" placeholder="Password"/>
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button type="submit" className="btn btn-default">Sign in</button>
</div>
</div>
</form>
</div>
)
}
});
var Homepage = React.createClass({
render: function () {
return(
<div>
<div className="container">
<Title>{this.props.children}</Title>
<Login>{this.props.children}</Login>
</div>
</div>
)
}
});
ReactDOM.render(<Homepage/>, document.getElementById('app'));
In my opinion the second way is much cleaner and is not dependent on other components. But I am just figuring out what way is standard.
this is straight from the React documentation:
When designing interfaces, break down the common design elements
(buttons, form fields, layout components, etc.) into reusable
components with well-defined interfaces. That way, the next time you
need to build some UI, you can write much less code. This means faster
development time, fewer bugs, and fewer bytes down the wire.
The beauty of React is being able to structure your application into simple, reusable components and have the option to pass data from the parent to the child components. So by having all your components in one file it's basically defeating the main objective of React.
I personally like to have an index file that handles my middleware and routes, and then a parent file for each section that handles imports and passing data down.
Related
I am creating a CV Application project and I have a button that allows the user to Add Work Experience. When the user clicks the button a form pops up and they are able to fill the information out and click Submit.
I'm trying to make it so once the user hits Submit, the form div stays hidden until the user clicks Add Work Experience again. I've made something similar before in vanilla JS where I simply changed the forms class from display: block to display: none but that doesn't seem possible in React.
import React, { Component } from "react";
class WorkExperience extends Component {
render() {
const workExperience = [
{
title: "title",
company: "company",
location: "location",
description: "description",
},
];
return (
<>
<div id="content" className="content">
<h1 className="title">Work Experience</h1>
<div className="work-experience">
<p>Job Title: {workExperience[0].title}</p>
<p>Company: {workExperience[0].company}</p>
<p>Location: {workExperience[0].location}</p>
<p>Description: {workExperience[0].description}</p>
</div>
</div>
<button className="form-btn">+ Add Work Experience</button>
</>
);
}
}
export default WorkExperience;
And here is the form code I am currently using. This is the form I want to show/hide after clicking the Add Work Experience button shown above.
<form>
<label for="title">Job Title</label>
<input id="title" className="form-row" type="text" name="title" />
<label for="company">Company</label>
<input className="form-row" type="text" name="company" />
<label for="location">Location</label>
<input className="form-row" type="text" name="location" />
<label for="description">Job Description</label>
<textarea rows="4" cols="50" name="description"></textarea>
<button className="save">Save</button>
<button className="cancel">Cancel</button>
</form>
You can use an if statement or a ternary to return different jsx. That would look something like this. There are other ways as well, however this is a basic example of something you could do.
<>
{
shouldShow ?
(
<div id="content" className="content">
<h1 className="title">Work Experience</h1>
<div className="work-experience">
<p>Job Title: {workExperience[0].title}</p>
<p>Company: {workExperience[0].company}</p>
<p>Location: {workExperience[0].location}</p>
<p>Description: {workExperience[0].description}</p>
</div>
</div>
<button className="form-btn">+ Add Work Experience</button>
) : (
<form>
<label for="title">Job Title</label>
<input id="title" className="form-row" type="text" name="title" />
<label for="company">Company</label>
<input className="form-row" type="text" name="company" />
<label for="location">Location</label>
<input className="form-row" type="text" name="location" />
<label for="description">Job Description</label>
<textarea rows="4" cols="50" name="description"></textarea>
<button className="save">Save</button>
<button className="cancel">Cancel</button>
</form>
)
}
</>
Where shouldShow is what determines whether the form is showing or not.
The benefit to this is that if the form is showing, the other content is not added to the DOM and vice versa.
shouldShow would be a variable you could add to state, and when the button is clicked, you toggle the state variable, causing a re-render.
https://reactjs.org/docs/state-and-lifecycle.html
You could also choose to render styles depending on whether or not that component is showing, the key being that boolean state variable that is re-rendering the component.
Use Repeater Felilds to add User Work Experience. It's so easy to handle like this.
Repeater Component
import React from "react";
const Repeater = ({ inputFields, setInputFields }) => {
const handleFormChange = (index, event) => {
let data = [...inputFields];
data[index][event.target.name] = event.target.value;
setInputFields(data);
};
const removeFields = (index) => {
let data = [...inputFields];
data.splice(index, 1);
setInputFields(data);
};
return (
<div className="row">
{inputFields.map((input, index) => {
return (
<>
<div className="form-group col-sm-12 col-md-4 mb-3">
<div className="controls">
<input
type="text"
className="form-control inputset"
id="title"
placeholder="title"
name="title"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.title}
onChange={(event) => handleFormChange(index, event)}
/>
<div className="help-block" />
</div>
</div>
<div className="form-group col-sm-12 col-md-4 mb-3">
<div className="date-picker">
<input
type="text"
className="pickadate form-control inputset"
value={input.company}
onChange={(event) => handleFormChange(index, event)}
name="company"
id="pass"
data-validation-required-message="This field is required"
data-toggle="tooltip"
data-trigger="hover"
data-placement="top"
data-title="Date Opened"
data-original-title=""
required
/>
</div>
</div>
<div className="form-group col-sm-12 col-md-4 d-flex mb-3">
<input
type="text"
className="form-control inputset"
id="location"
placeholder="location"
name="location"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.location}
onChange={(event) => handleFormChange(index, event)}
/>
<input
type="text"
className="form-control inputset"
id="description"
placeholder="description"
name="description"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.description}
onChange={(event) => handleFormChange(index, event)}
/>
{inputFields.length === 1 ? null : (
<button
type="button"
className=" d-flex justify-content-center align-items-center ml-1 btn"
onClick={() => {
removeFields();
}}
>
<i className="uil-trash-alt" />
</button>
)}
</div>
</>
);
})}
</div>
);
};
export default Repeater;
Main Component
use these as states and pass the objects to the Repeater Component. First, the state is empty and when the user clicks on the button Add More Experience The files auto-show.
const [inputFields, setInputFields] = useState([
{ degree_title: "", institue: "", end_date: "" },
]);
const addFields = () => {
let newfield = { degree_title: "", institue: "", end_date: "" };
setInputFields([...inputFields, newfield]);
};
<Repeater
inputFields={inputFields}
setInputFields={setInputFields}
addFields={addFields} />
I wish this solution helps you :) Make sure to change the state object according to your requirements.
This question already has an answer here:
Problem in redirecting programmatically to a route in react router v6
(1 answer)
Closed 11 months ago.
This is the my login.js page code I want redirect the new page after click the button. I tried several methods but problem not solve. All things are work correctly. but I don't know how to link the page after the api return result in loginClick function. I Added this line in the code refer some tutorial but its not work.
this.props.history.push('/add');
I am new to the react js, I don't know about the react well. please help me.
import React,{Component} from 'react';
import { variables } from '../../Variables';
export class Login extends Component{
constructor(props){
super(props);
this.state={
login:[],
name:"",
password:"",
redirect: false
}
}
changelogindetailsname = (e)=>{
this.setState({name:e.target.value})
}
changelogindetailspass = (e)=>{
this.setState({password:e.target.value})
}
loginClick(){
fetch(variables.API_URL+'login',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
name:this.state.name,
password:this.state.password
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.props.history.push('/add');
},(error)=>{
alert('Faild');
})
}
render(){
const{
name,
password
}=this.state;
return(
<div>
<center>
<h1></h1>
<hr/>
<h3>Welcome Back !</h3>
<p></p>
<div className="container">
<br/>
<br/>
<br/>
<div className="row">
<div className="col">
</div>
<div className="col">
</div>
<div className="col-4">
<style>{"\ .rr{\ float:left;\ }\ "} </style>
<style>{"\ .bb{\ float:right;\ }\ "} </style>
<div className="mb-3">
<label className="form-label rr d-flex"> Username</label>
<div className="input-group input-group-lg">
<input type="text" className="form-control " id="formGroupExampleInput" placeholder="Username"
value={name}
onChange={this.changelogindetailsname}/>
</div>
</div>
<div className="mb-3">
<label className="form-label rr d-flex">Password</label>
<div className="input-group input-group-lg">
<input type="password" className="form-control" id="formGroupExampleInput2" placeholder="Password"
value={password}
onChange={this.changelogindetailspass}/>
</div>
</div>
<div className="d-flex mb-3">
Forgot your password?
</div>
<div className="col">
<div className="form-check rr">
<input className="form-check-input" type="checkbox" value="" id="flexCheckDefault"/>
<label className="form-check-label" htmlFor="flexCheckDefault">
Remember me
</label>
</div>
</div>
<div className="col">
<button type="button" className="btn btn-success bb"
onClick={()=>this.loginClick() } >Login</button>
</div>
<br/>
<br></br>
<hr/>
<p>Don't have an account?</p>
<div className="mb-3">
<button type="button" className="btn btn-light d-flex"
>Sign up for Muessoze</button>
</div>
</div>
<div className="col">
</div>
<div className="col">
</div>
</div>
</div>
</center>
</div>
)
}
}
Firstly you should import this:
import { useHistory } from 'react-router-dom';
then:
const history = useHistory();
after all, you can use this in your method:
loginClick(){
fetch(variables.API_URL+'login',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
name:this.state.name,
password:this.state.password
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
history.push('/add');
},(error)=>{
alert('Faild');
})
}
Take a look at the react router API, if you want to use the this.props.history.push() method you will need to wrap your component with the withRouter HOC wrapper from the react dom api.
See : https://reactrouter.com/docs/en/v6/getting-started/tutorial
I am trying to make a ReactJS form in which there is a button which, once pressed, alters the value of an input tag. Every time I press the button, the text is changed, but the page reloads, and the textarea returns to being blank. I've searched up on this issue a little and found this thread : Reactjs every time refreshing page on setState.
However, the solution to this problem( shouldComponentUpdate() {return false;} ) ended up making it so that the text of the inputarea didn't change at all. Here is my code:
import React, { Component } from 'react';
export default class Header extends Component {
state = {
cep : "",
address : "",
}
searchCEP(){
this.setState({ address : "Adress" });
}
render(){
return (
<div>
<div id="host-form" className="row">
<div className="col s1"></div>
<form className="col s10">
<div className="row">
<div className="input-field col s6">
<input placeholder='"Terreno para churrasco"' id="title" type="text" className="validate"/>
<label htmlFor="title">Título</label>
</div>
<div className="input-field col s2">
<input id="cep" type="text" className="validate" defaultValue={this.state.cep}/>
<label htmlFor="cep">CEP</label>
</div>
<div id="buscar-cep" className="col s1">
<button onClick={() => this.searchCEP()} className="waves-effect blue waves-light btn">Buscar por CEP</button>
</div>
<div className="col s2"></div>
</div>
<div className="row">
<div className="input-field col s12">
<input placeholder='"Terreno de 500 metros quadrados com uma linda vista do Cristo Redentor...\"' id="description" type="text" className="validate"/>
<label htmlFor="description">Descrição</label>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<input id="address" type="text" className="validate" defaultValue={this.state.address}/>
<label htmlFor="address">Endereço</label>
</div>
</div>
</form>
</div>
</div>
);
}
};
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I hope this is enough to understand my problem. Thanks in advance for any help.
from reading what you said the best case reason as to why the page reloads, from past exprience is that when you call the function you do not prevent the default action of the button within the form so you could try
"""
searchCEP(e){
e.preventDefault();
this.setState({ address : "Adress" });
}
"""
<div id="buscar-cep" className="col s1">
<button onClick={(e) => this.searchCEP(e)} className="waves-effect blue waves-light btn">Buscar por CEP</button>
</div>
"""
Since
hope this helps
You can make following changes
<div id="buscar-cep" className="col s1">
<button onClick={(e) => this.searchCEP(e)} className="waves-effect blue waves-light btn">Buscar por CEP</button>
</div>
and in searchCEP function, do the following changes:
searchCEP(e){
e.preventDefault();
this.setState({ address : "Adress" });
}
This will stop the reloading
You should stop the default behavior of the form element :
<form onSubmit={(e) => e.preventDefault()}
I should have both question input and answer input in a <Field/>. Because of that redux-form docs tells me to use <Fields/>.
<Fields names={['question1', 'answer1']}
component={this.renderInputGroupField} />
<Fields names={['question2', 'answer2']}
component={this.renderInputGroupField} />
<Fields names={['question3', 'answer3']}
component={this.renderInputGroupField} />
rendering fields with this
renderInputGroupField(fields){
return(
<div className="form-group d-block">
<div className="form-group input-group">
<select className="form-select" >
<option>Multiple-Choice</option>
<option>Open-Ended</option>
</select>
<input {...fields.question1.input}
type="text"
className="form-input"
placeholder="Type your question..."/>
</div>
<div className="form-group">
<input {...fields.answer1.input}
type="text"
className="form-input"
placeholder="Comma-separated answer choices" />
</div>
</div>
);
}
To make renderInputGroupField work, I should add {...fields.answer1.input} into <input /> as above. Here is the problem. Names that are passed into fields are different and I can't find a way to change ...fields.answer1.input to ...fields.answer2.input dynamically.
I am not sure if I was able to explain it properly. Thanks for your help.
So, it seems you want to use the renderInputGroupField as a reusable component. Quickly testing, it looks like redux-form also sends back that list of names you originally gave it. You should be able to access those properties of fields that you listed in the names array using their index in that array, like below.
return(
<div className="form-group d-block">
<div className="form-group input-group">
<select className="form-select">
<option>Multiple-Choice</option>
<option>Open-Ended</option>
</select>
<input {...fields[fields.names[0]].input}
type="text"
className="form-input"
placeholder="Type your question..."/>
</div>
<div className="form-group">
<input {...fields[fields.names[1]].input}
type="text"
className="form-input"
placeholder="Comma-separated answer choices" />
</div>
</div>
);
How I can optimize my HTML markup? In this case (I use Sublime Text 2), I choose "set syntax JSX" for highlighting and emeet won't work at first.
At second - more preferable for me, to keep markup in some .tmpl files.
It is possible in this case? For example, my render method:
render: function() {
var result = this.state.data;
var self = this;
var inputNodes = result.map && result.map(function(item, keyIndex) {
return (
<div className="row" key={keyIndex} className={'inputs-row ' + (item.disabled ? 'inputs-row_disabled':'')}>
<div className="col-md-12">
<div className="col-md-6 form-group">
<div className="input-group">
<div className="input-group-addon">
<i className="fa fa-info fa-fw"></i>
</div>
<input className="key-input form-control" type='text' value={item.name} onClick={self.onInputKeyClick.bind(self,item)} readOnly />
</div>
</div>
{
item.values.map(function(value, valIndex) {
return (
<div className="col-md-6 form-group" key={valIndex}>
<div className="input-group">
<input className="key-input form-control" type='text' value={value.name} onChange={self.changeLocalizedValue.bind(self, value, valIndex, keyIndex)} />
<div className="input-group-addon input-group-addon_btn">
<button className="btn btn-default btn_right-radius" onClick={self.sendItem.bind(self, value)}>
<i className="fa fa-check fa-fw"></i>
</button>
</div>
</div>
</div>
)
})
}
</div>
</div>
);
});
return (
<div>
<div>{inputNodes}</div>
<button onClick={self.sendAll}>SEND ALL</button>
</div>
)
}
P.S. I use: gulp and browserify.
There are libraries that lets you extract React templates into their own files, but I think one of the strengths of React is that the markup is co-located with the view logic. If the markup is changed then the view logic often has to be changed, and vice versa. Keeping them in the same file makes that more convienient.
I would recommend you to create more components. Take this chunk of JSX for example:
<div className="col-md-6 form-group">
<div className="input-group">
<div className="input-group-addon">
<i className="fa fa-info fa-fw"></i>
</div>
<input className="key-input form-control" type='text' value={item.name} onClick={self.onInputKeyClick.bind(self,item)} readOnly />
</div>
</div>
Does very little, and it's not very readable what the purpose of that chunk is. If you instead extract that into another component and give it a meaningful name, your markup won't look as cluttered, and you get better readability.