I am new to REACT and the MERN Stack and try to understand everything. But sometimes, it seems that the simplest things do not want to get into my head.
I hope that, one day, I will understand it all. Until then it still seems a long way away. Anyway. I am starting with a simple MERN app. All users should be displayed on the start page. On a separate "page" there should be a create users form. For now, the users are displayed on the home screen but when I switch back from the "create users page" they dissappeared. Furthermore the input form do not work (validation error). When checking get and posts requests from my backend with Thunder Client everthing works, so I suppose, this might be something to do with the frontend. Sorry for my wording. I am a programming newbie.
I hope it is somewhat understandable. What am I doing wrong? I would be so happy, if anyone could help. Thank you!
client/src/App.js
import React from "react";
import { Routes, Route } from "react-router-dom";
import AllUsers from "./pages/AllUsers";
import Navigation from "./components/Navigation";
import CreateUser from "./pages/CreateUser";
import "./App.css";
function App() {
return (
<div className="App">
<Navigation />
<Routes>
<Route path="/" element={<AllUsers />} />
<Route path="create-User" element={<CreateUser />} />
</Routes>
</div>
);
}
export default App;
client/src/components/Navigation.js
import React from "react";
import { Link } from "react-router-dom";
const Navigation = () => {
return (
<header className="bg-background border-t-0 shadow-none">
<nav className="bg-navigation bg-opacity-40 rounded-t-xs flex justify-around h-12 p-3 ">
<Link to="/create-user">Create User</Link>
<Link to="/">
<img id="workshop-icon" src="../assets/home.svg" alt="home button" />
</Link>
</nav>
</header>
);
};
export default Navigation;
client/src/AllUsers.js
import React from "react";
import { useState, useEffect } from "react";
import Axios from "axios";
const AllUsers = () => {
const [listOfUsers, setListOfUsers] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/getUsers").then((response) => {
setListOfUsers(response.data);
});
}, []);
return (
<div className="App">
<div className="usersDisplay">
{listOfUsers.map((user) => {
return (
<div key={user._id}>
<h1>Name: {user.name}</h1>
<h1>Age: {user.age}</h1>
<h1>Username: {user.username}</h1>
</div>
);
})}
</div>
</div>
);
};
export default AllUsers;
client/src/createUser.js
import React from "react";
import { useState } from "react";
import Axios from "axios";
const CreateUser = () => {
const [listOfUsers, setListOfUsers] = useState([]);
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [username, setUsername] = useState("");
Axios.post("http://localhost:3001/createUser", {
name,
age,
username,
}).then((response) => {
setListOfUsers([
...listOfUsers,
{
name,
age,
username,
},
]);
});
return (
<div className="input">
<div>
<input
type="text"
placeholder="Name..."
onChange={(event) => {
setName(event.target.value);
}}
/>
<input
type="number"
placeholder="Age..."
onChange={(event) => {
setAge(event.target.value);
}}
/>
<input
type="text"
placeholder="Username..."
onChange={(event) => {
setUsername(event.target.value);
}}
/>
<button onClick={CreateUser}> Create User </button>
</div>
</div>
);
};
export default CreateUser;
Related
I'm fairly new Ionic React and trying to create an App using Ionic framework. I have a use case where I would like to redirect to another page upon a button press and validation from a function.
Here is the component I am working with
import React, { useState } from 'react';
import {
IonContent,
IonHeader,
IonPage,
IonTitle,
IonToolbar,
IonInput,
IonButton,
IonRow,
IonCol,
useIonViewWillEnter,
useIonViewWillLeave,
IonLabel
} from '#ionic/react';
import './LogIn.css'
import MainMenu from "../MainMenu";
const LogIn: React.FC<{register?: boolean; onClose?: any}> = () => {
const [email, setEmail] = useState<string>();
const [password, setPassword] = useState<string>();
function handleLoginButtonPress() {
if (validateEmail() && password !== undefined && password.trim() !== "") {
// Network call here to check if a valid user
console.log("valid email")
return <MainMenu/>
}
}
function validateEmail () {
if (email !== undefined && email.trim() !== "") {
const regexp = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regexp.test(email);
}
return false;
}
useIonViewWillEnter(() => {
console.log("Entering LogIn");
});
useIonViewWillLeave(() => {
console.log("Exiting LogIn");
});
return (
<IonPage id="loginIonPage">
<IonHeader>
<IonToolbar color="primary" mode="md">
<IonTitle class="ion-text-center">Login or Register</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent id="loginPage">
<div id="loginDialog">
<form>
<IonLabel>Email</IonLabel>
<IonRow>
<IonCol id="userName">
<IonInput
name="email"
value={email}
onIonChange={e => setEmail(e.detail.value!)}
clearInput
type="email"
placeholder="Email"
class="input"
padding-horizontal
clear-input="true"
required/>
</IonCol>
</IonRow>
<IonLabel>Password</IonLabel>
<IonRow>
<IonCol id="password">
<IonInput
clearInput
name="password"
value={password}
onIonChange={e => setPassword(e.detail.value!)}
type="password"
placeholder="Password"
class="input"
padding-horizontal
clear-input="true"
required/>
</IonCol>
</IonRow>
</form>
</div>
<div id="buttons">
<IonButton
onClick={handleLoginButtonPress}
type="submit"
strong={true}
expand="full"
style={{ margin: 20 }}>
Log in
</IonButton>
<IonButton
routerLink="/registerUser"
type="submit"
strong={true}
expand="full"
style={{ margin: 20 }}>
Register
</IonButton>
</div>
</IonContent>
</IonPage>
);
};
export default LogIn;
How can I redirect to another page from the function handleLoginButtonPress which is invoked upon clicking on Login button. I tried reading through ionic doc but that did not help as it redirects whenever there is button click or click on an IonElement like IonLabel.
Use react-router-dom hooks
https://reacttraining.com/react-router/web/api/Hooks/usehistory
import { useHistory } from "react-router-dom";
const ExampleComponent: React.FC = () => {
const history = useHistory();
const handleLoginButtonPress = () => {
history.push("/main");
};
return <IonButton onClick={handleLoginButtonPress}>Log in</IonButton>;
};
export default ExampleComponent;
Thanks, #MUHAMMAD ILYAS and it would have worked for me. But I managed to leverage the react state as below, I have added as an answer as I could not format the code there,
const ValidateUser : React.FC = () => {
const [login, setLogin] = useState(false);
function isUserLoggedIn() {
return login;
}
return(
<IonReactRouter>
<IonRouterOutlet>
<Route path="/" render={() => isUserLoggedIn()
? <MainMenu/>
: <LogIn setUserLoggedIn={() => {setLogin(true)}}/>} exact={true}/>
</IonRouterOutlet>
</IonReactRouter>
);
};
const LogIn: React.FC<{setUserLoggedIn?: any}> = ({setUserLoggedIn}) => {
.
.
function onLoginButtonPress() {
setUserLoggedIn();
}
}
Thanks
I can't seem to be able to login to my app that I'm making when I click on my "Log in with Facebook" button. Also, I'm using React JS. I think it might have something to do with not having REACT_APP_FACEBOOKLOGIN=######### (where ######### is my Facebook Developer ID) inside of a .env file.
import React, { Component } from 'react';
import logo from './logo.png';
import FacebookLogin from 'react-facebook-login';
import Sidebar from "react-sidebar";
import LeaveGroup from "./components/LeaveGroup";
// import firebase from "./utils/firebase.js";
import { GoogleApiWrapper } from 'google-maps-react';
import MapBox from "./components/MapBox";
// import ReactDOM from 'react-dom'
import ChatBox from "./components/ChatBox";
import API from "./utils/API";
import './App.css';
import CreateGroup from './components/CreateGroup/CreateGroup';
require("dotenv").config();
class App extends Component {
constructor(props) {
super(props);
this.state = {
sidebarOpen: true,
name: "",
id: "",
chatText: "",
messagesArray: [],
groupName: "",
};
this.onSetSidebarOpen = this.onSetSidebarOpen.bind(this);
}
onSetSidebarOpen(open) {
this.setState({ sidebarOpen: open });
};
componentDidMount() {
this.loadUsers();
}
loadUsers = () => {
API.getUsers()
.then(res =>
this.setState({ users: res.data }, () => console.log("loadUsers Data: ", res.data))
)
.catch(err => console.log(err));
};
saveUsers = (data) => {
API.saveUser(data)
.then(res =>
console.log(res))
}
handleOnClick = event => {
event.preventDefault();
if (this.state.name) {
API.saveUser({
name: this.state.name,
})
.then(res => this.loadUsers())
.catch(err => console.log(err));
}
};
responseFacebook = (response) => {
console.log(response);
this.setState({ name: response.name, id: response.id })
this.saveUsers(response);
}
render() {
return (
<div className="App">
<Sidebar
sidebar={<b>
<button onClick={() => this.onSetSidebarOpen(false)}>
×
</button>
<div>
<img id="logo-image" src={logo} alt="catchup-app-logo" />
</div>
<div className="about-text">
{/* <p>The CatchUp! app allows you to
create, share and join private location based groups.
</p> */}
</div>
<div
style={{ padding: 40 }}>
<br />
<FacebookLogin
appId={process.env.REACT_APP_FACEBOOKLOGIN}
autoLoad={true}
reauthenticate={true}
fields="name,email,picture"
callback={this.responseFacebook}
/>
<br />
<br />
</div>
{/* Create group box */}
<CreateGroup
groupName={this.state.groupName}
groupMember={this.state.name}
/>
{/* Join group box */}
<div className="text-box">
<p>
<button class="btn btn-dark" type="button" data-toggle="collapse" data-target="#collapseExample1" aria-expanded="false" aria-controls="collapseExample">
Join a Group
</button>
</p>
<div class="collapse" id="collapseExample1">
<div class="card card-body">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Group Name" aria-label="Group Name" aria-describedby="button-addon2" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" id="button-addon">Join</button>
</div>
</div>
</div>
</div>
</div>
<ChatBox
name={this.state.name}
groupName={this.state.groupName}
messagesArray={this.state.messagesArray}
/>
</b>}
open={this.state.sidebarOpen}
onSetOpen={this.onSetSidebarOpen}
styles={{ sidebar: { background: "white" } }}
>
<button onClick={() => this.onSetSidebarOpen(true)}>
<i class="fas fa-bars"></i>
</button>
</Sidebar>
<br />
<br />
<MapBox
gProps={this.props.google}
gZoom={17}
gOnMarkerClick={this.gOnMarkerClick}
gName={this.state.name}
gGroupName={this.state.groupName}
gOnClose={this.onInfoWindowClose}
/>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: `${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}`
})(App)
I want this to be able to get this to work so move onto logging in a user into my MongoDB.
I'm using v1.1.0 of material-ui in React 16.3.2. I'm trying to create a landing page similar to Showcase - Local Insights
where the dialog has opacity (Find foreclosures). I'm trying to use PaperProps for Dialog component described here Dialog doc
Here's a component I've created to try to do this.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogTitle from '#material-ui/core/DialogTitle';
import ForwardIcon from '#material-ui/icons/Forward';
import Input from '#material-ui/core/Input';
import FormControl from '#material-ui/core/FormControl';
import Slide from '#material-ui/core/Slide';
const styles = theme => ({
dialogPaper: {
opacity: 0.5,
border: '#FF0000 1px solid',
},
button: {
margin: '30px'
}
});
function Transition(props) {
return <Slide direction="up" {...props} />;
}
class SignInDialog extends React.Component {
state = {
open: false,
username: ''
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
render() {
const { classes } = this.props;
return (
<div>
<Button variant="fab" color="primary" aria-label="add" className={classes.button} onClick={this.handleClickOpen}>
<ForwardIcon />
</Button>
<Dialog
PaperProps={styles.dialogPaper}
open={this.state.open}
TransitionComponent={Transition}
onClose={this.handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">WELCOME</DialogTitle>
<DialogContent>
<p>SIGN IN</p>
<FormControl className={classes.formControl}>
<Input
value={this.state.searchString}
onChange={this.handleChange('search')}
id="siginin-input"
placeholder="Enter your username"
/>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleClose} color="primary">
Continue
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
SignInDialog.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(SignInDialog);
I haven't been able to figure out how to get the Dialog to take the styles. What is needed to get PaperProps to work?
If you want to use PaperProps you have to specify the props of the Paperfor which you are applying style.
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>
You can also use classes property and override the style
<Dialog
classes={{paper:classes.dialogPaper}}
/>
The correct way to overide paper props is by using classNames
<Dialog
PaperProps={{ className: classNames(classes.dialogPaper) }}/>
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>
I am new in developing application in react js and i am very confused which one is the best way / best practice for working with forms, and validating forms in react js other than controlled / uncontrolled method. Any guidance will be very helpful for me, Thank in advance.
Your form validation and handling form values becomes much easier if you use redux-form.
https://redux-form.com/7.3.0/docs/gettingstarted.md/
This is a sample react registration form,you ll be able to get an idea
Home.jsx
'use strict';
import React, {Component} from 'react';
import AddBook from './AddBook';
import axios from 'axios';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
books:[],
authors:[]
};
this.addBook = this.addBook.bind(this);
}
componentWillMount(){
axios.get(`http://localhost:8095/authors`)
.then(res=>{
const authors=res.data;
this.setState({authors});
console.log(res);
})
}
addBook(Name,ISBN,Author,Price,Year,Publisher){
axios.post(`http://localhost:8095/books`,{
Name:Name,
ISBN:ISBN,
Author:Author,
Price:Price,
Year:Year,
Publisher:Publisher
}).then(res=>{
console.log(res);
})
}
render() {
return <div>
<AddBook
addBook={this.addBook}
authors={this.state.authors}
/>
</div>
}
}
AddBook.jsx
'use strict';
import React, {Component} from 'react';
import { Button } from 'react-bootstrap';
export default class AddBook extends Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(event){
event.preventDefault();
this.props.addBook(
this.nameInput.value,
this.ISBNInput.value,
this.AuthorInput.value,
this.PriceInput.value,
this.YearInput.value,
this.PublisherInput.value
);
this.nameInput.value='';
this.ISBNInput.value='';
this.AuthorInput.value='';
this.PriceInput.value='';
this.YearInput.value='';
this.PublisherInput.value='';
}
render() {
return <div>
<form>
<header>Add Books</header>
<div><input placeholder="Name" ref={nameInput=>this.nameInput=nameInput}/></div>
<div><input placeholder="ISBN" ref={ISBNInput=>this.ISBNInput=ISBNInput}/></div>
<div><select ref={AuthorInput=>this.AuthorInput=AuthorInput}>
<option selected disabled >--author name--</option>
{
this.props.authors.map(author=>
<option key={author._id}>{author.fname}</option>
)
}
</select>
</div>
<div><input placeholder="Price" ref={PriceInput=>this.PriceInput=PriceInput}/></div>
<div><input placeholder="Year" ref={YearInput=>this.YearInput=YearInput}/></div>
<div><input placeholder="Publisher" ref={PublisherInput=>this.PublisherInput=PublisherInput}/></div>
<div><Button onClick={this.onSubmit}>Add Book</Button></div>
</form>
</div>
}
}
View.jsx
'use strict';
import React, {Component} from 'react';
import axios from 'axios';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
books:[]
};
}
componentWillMount(){
axios.get(`http://localhost:8095/books`).then(res=>{
const books=res.data;
this.setState({books});
console.log(books);
})
}
render() {
return <div>
<h2>This is the available book list</h2>
<div>
{
this.state.books.map(book =>
<div>
<span key={book._id}>Name:{book.Name}</span>
</div>
)
}
</div>
</div>
}
}
I am also new to React,so there may be redundancies in code.But this works fine.Hope this will help.
I have to implement a form with a bit less than 30 different fields.
So I decided to split them in 2 differents container component with two tabs to navigate between them.
I use redux-form to handle the data binding.
For on component I can get the value from handleSubimit of one component. But the final validation must be in the last tab only. From here I only have access to the value of the second tab. Like the data from the store where wipe out.
How can I access the store where my previous data should be ?
TabNavigationBar.js
import React from 'react';
import TabNavigationItem from './TabNavigationItem';
const TabNavigationBar = ({ onTabChange, activeTab }) => {
const tabList = [
{ hasIcon: 'fas fa-user-circle', hastext: 'Information Utilisateur' },
{ hasIcon: 'fas fa-file-alt', hastext: 'Informations contrat' }
];
const clickOnTab = tabNumer => {
onTabChange(tabNumer);
};
return (
<div className="columns">
<div className="column is-offset-one-quarter-desktop is-offset-one-thirds-tablet is-half-desktop is-one-thirds-tablet">
<div className="tabs is-toggle is-fullwidth">
<ul>
{tabList.map((tab, i) => (
<TabNavigationItem
key={i}
tabSelected={() => clickOnTab(i)}
hasClass={activeTab === i ? 'is-active' : ''}
hasIcon={tab.hasIcon}
hasText={tab.hastext}
/>
))}
</ul>
</div>
</div>
</div>
);
};
export default TabNavigationBar;
UserForm.js
import React from 'react';
import { reduxForm } from 'redux-form';
import CiviliteRadioButton from './CiviliteRadioButton';
import NameInputs from './NameInputs';
import AddressInputs from './AddressInputs';
import MailAndDOB from './MailAndDOB';
import TelephoneInputs from './TelephoneInputs';
let UserForm = ({ handleSubmit }) => {
return (
<div>
<CiviliteRadioButton />
<NameInputs />
<AddressInputs />
<MailAndDOB />
<TelephoneInputs />
</div>
);
};
UserForm = reduxForm({
form: 'form1',
initialValues: {
user: {
adresse: {
country: 'France'
},
civilite: 'Madame'
}
}
})(UserForm);
export default UserForm;
ContractForm.js
import React from 'react';
import { reduxForm } from 'redux-form';
import InputItem from '../InputItem';
import ContratInputsList from './contratInputList';
let ContratForm = ({ handleSubmit }) => {
const submit = values => {
console.log(values);
};
return (
<div>
<div className="columns is-multiline ">
{ContratInputsList.map((item, i) => {
return (
<div className="column is-half" key={i}>
<InputItem spec={item.spec} />
</div>
);
})}
</div>
<div className="columns">
<div className="column">
<div className="field is-grouped is-grouped-right">
<input
className="button is-primary"
onClick={handleSubmit(submit)}
type="submit"
value="Envoyer"
/>
</div>
</div>
</div>
</div>
);
};
ContratForm = reduxForm({
form: 'form2'
})(ContratForm);
export default ContratForm;
EDIT
When I click on my tabs, redux-form/DESTROY is called and erase form1's data.
Try setting destroyOnUnmount flag to false in reduxForm(options).