I am new to React.js and material-ui. I am trying to make a simple sign up form, but I got an error. I have tested my backend on insomnia and all its routes work, so I believe my error is on my front. My sign up script is this one below. By the way, my error only says that it is a create error. Can you guys help me?
import React from 'react';
import { style } from './styles';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import Link from '#material-ui/core/Link';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import Container from '#material-ui/core/Container';
import { useState } from "react";
import api from "../../services/api"
function Cadastro() {
const classes = style();
const [nome, setNome] = useState("");
const [email, setEmail] = useState("");
const [cpf, setCpf] = useState("");
const [senha, setSenha] = useState("");
const [rg, setRg] = useState("");
const [data_nascimento, setDataNascimento] = useState("");
async function save(){
try{
await api.post('/cadastro', {
nome,
cpf,
email,
rg,
data_nascimento,
senha
})
}catch(err){
console.log(err)
}
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Cadastro
</Typography>
<form className={classes.form} noValidate>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
// value={nome}
required
fullWidth
id="nome"
label="Nome"
onChange={e => setNome(e.target.value)}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
fullWidth
id="cpf"
label="CPF"
// value={cpf}
onChange={e => setCpf(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
id="email"
label="Email"
// value={email}
onChange={e => setEmail(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
// value={senha}
label="Senha"
type="password"
id="senha"
onChange={e => setSenha(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
// value={rg}
label="RG"
id="rg"
onChange={e => setRg(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
// value={data_nascimento}
type="date"
id="data_nascimento"
onChange={e => setDataNascimento(e.target.value)}
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={save}
>
Cadastrar
</Button>
</form>
</div>
</Container>
);
}
export default Cadastro;
EDIT 1:
My error:
Error: "Request aborted"
createError createError.js:16
handleAbort xhr.js:73
index.js:36
The development server has disconnected.
Refresh the page if necessary. webpackHotDevClient.js:76
[HMR] Waiting for update signal from WDS... log.js:24
The index file is the code above.
Now, my api script is below:
import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:5000'
});
export default api;
Related
I'm trying to use text field from material ui and I use Box element and i got an error message saying that there is an error in box.js. Box.js is a built in file from material and i can't change it. Here's my component codes. I don't understand why the error is in box.js. How can i fix it?
import * as React from 'react';
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import styled from "styled-components";
import Layout from '../../Layouts/SideMenu';
import Stack from '#mui/material/Stack';
import TextField from '#mui/material/TextField';
import '#fontsource/roboto/300.css';
import '#fontsource/roboto/400.css';
import '#fontsource/roboto/500.css';
import '#fontsource/roboto/700.css';
const Wrapper = styled.section`
padding: 4em;
`;
export default function Create() {
const [age, setAge] = React.useState('');
return (
<Layout>
<Wrapper>
<form action="">
<Stack spacing={3} direction="column">
<h2>Form Tambah Siswa</h2>
<TextField id="outlined-basic" label="Nama" variant="outlined" />
<Box
component="form"
sx={{
'& > :not(style)': { m: 1, width: '25ch' },
}}
noValidate
autoComplete="off"
>
<TextField id="outlined-basic" label="Email" variant="outlined" />
</Box>
<Box
component="form"
sx={{
'& > :not(style)': { m: 1, width: '25ch' },
}}
noValidate
autoComplete="off"
>
<TextField id="outlined-basic" label="Password" variant="outlined" />
</Box>
<Box
component="form"
sx={{
'& > :not(style)': { m: 1, width: '25ch' },
}}
noValidate
autoComplete="off"
>
<TextField id="outlined-basic" label="Confirm Password" variant="outlined" />
</Box>
<Button variant="contained" type='submit'>Submit</Button>
</Stack>
</form>
</Wrapper>
</Layout>
)
}
I'm sending my react-hook-form field to another function component as a children. After pressing Submit Button, the field refreshes and the value inputed is deleted. What is the problem?
CodeSandBox example is here
My file App.js:
import React from "react";
import "./styles.css";
import { useForm } from "react-hook-form";
import { Box, Button, Grid, TextField } from "#material-ui/core";
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
It's always a good idea to move your sub-component into its own, otherwise, each re-render will mount and unmount your component.
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
https://codesandbox.io/s/agitated-darkness-leg7z?file=/src/App.js
I have React Router v5 with below code:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
const muiTheme = createMuiTheme({
palette: {
primary: {
main: '#2196f3'
}
},
overrides: {
MUIDataTableSelectCell: {
fixedHeaderCommon: {
backgroundColor: 'transparent',
},
},
MuiTableCell: {
sizeSmall: {
padding: '6px 0 6px 16px'
}
},
MuiTableRow: {
hover: {
cursor: 'pointer'
}
}
}
});
ReactDOM.render(<MuiThemeProvider theme={muiTheme}><App /></MuiThemeProvider>, document.getElementById('root'));
serviceWorker.unregister();
App.js
import {
// BrowserRouter as Router,
Switch,
Route,
Router,
// Link,
// useRouteMatch,
// useParams
} from "react-router-dom";
import history from 'history/browser';
import Dashboard from './common/components/Dashboard';
import Login from './common/components/Login';
import Test from './common/components/Test';
<Router history={history}>
<Switch>
<Route path="/test" component={Test} />
<Route path="/login" component={Login} />
<Route path="/" exact component={Dashboard} />
<Route component={Error404} />
</Switch>
</Router>
Login.js
import { useHistory } from "react-router-dom";
export default function Login() {
let history = useHistory();
const classes = useStyles();
const storedToken = localStorage.getItem('token');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [remember, setRemember] = useState(false);
const [fetchError, setFetchError] = useState(null);
async function login(e) {
e.preventDefault();
try {
const data = await ApiClient.post(`/api/auth`, { email: email, password: password, remember: remember });
localStorage.setItem('token', data.token);
setFetchError(null);
history.push('/test');
} catch (err) {
if(err.response.status === 401) {
setFetchError('Unauthorized access, please login again.');
}
}
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Login
</Typography>
<form className={classes.form} noValidate onSubmit={login}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
onChange={(e) => setEmail(e.target.value)}
value={email}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={(e) => setPassword(e.target.value)}
value={password}
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
onChange={(e) => setRemember(e.target.value)}
value={remember}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
);
}
Whenever I submit with correct credentials I get 200 response code from the server with JWT token but after history.push('/test'); on login function, I don't get the Route match with /test instead it goes to Error404 catch all route.
How is this possible?
It seems like a bug in history version 5. See this comment. When I downgraded to 4.10.1 it immediately worked
Below is the functional signup component in React. I have one particular problem with the DatePicker component. It renders correctly on the sign up form. When I click on the submit button, it does not give me the selected date but instead it sends me the initial state of the component. Other states such as fullname, password and email are updated accordingly.
To prove that the date was not updated, I tried putting "null" in the useState() and when I get the result in the database, as expected the date is of a "null" type. How do I update the initial state to the updated state?
import React, { useState, useContext, Fragment } from "react";
import Avatar from "#material-ui/core/Avatar";
import Button from "#material-ui/core/Button";
import CssBaseline from "#material-ui/core/CssBaseline";
import TextField from "#material-ui/core/TextField";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import Link from "#material-ui/core/Link";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import { signup } from "./auth-api";
import DatePicker from "./DatePicker";
import Copyright from "./Copyright";
import AuthApi from "../utils/AuthApi";
import { MuiPickersUtilsProvider } from "#material-ui/pickers"; //Date picker util provider
import DateFnsUtils from "#date-io/date-fns"; // Date util library
// We can use inline-style
const style = {
background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
borderRadius: 3,
border: 0,
color: "white",
height: 48,
padding: "0 30px",
boxShadow: "0 3px 5px 2px rgba(255, 105, 135, .3)",
};
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center",
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function SignUp() {
const classes = useStyles();
const joindate = new Date();
const [fullname, setFullname] = useState();
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [dateofbirth, setSelectedDate] = useState(new Date());
const handleOnChange = (e) => {
if (e.target.name === "fullname") {
setFullname(e.target.value);
} else if (e.target.name === "username") {
setEmail(e.target.value);
} else if (e.target.name === "password") {
setPassword(e.target.value);
}
};
const handleDateChange = (date) => {
setSelectedDate(date);
};
const authApi = React.useContext(AuthApi);
const handleSignUp = async (e) => {
e.preventDefault();
const res = await signup({
joindate,
fullname,
email,
password,
dateofbirth,
});
if (res.data.auth) {
authApi.setAuth(true);
}
//console.log(res);
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<form className={classes.form} noValidate>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
autoComplete="fname"
name="fullname"
variant="outlined"
required
fullWidth
id="fullName"
label="Full Name"
autoFocus
onChange={handleOnChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="username"
autoComplete="email"
onChange={handleOnChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={handleOnChange}
/>
</Grid>
<Grid item xs={12}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Fragment>
<DatePicker
inputVariant="outlined"
required
fullWidth
id="dob"
name="dob"
disableFuture
openTo="year"
format="dd-MM-yyyy"
label="Date of Birth"
views={["year", "month", "date"]}
value={dateofbirth}
onChange={handleDateChange}
/>
</Fragment>
</MuiPickersUtilsProvider>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
style={style}
className={classes.submit}
onClick={handleSignUp}
>
Sign Up
</Button>
<Grid container justify="flex-end">
<Grid item>
<Link href="/signin" variant="body2">
Already have an account? Sign in
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={5}>
<Copyright />
</Box>
</Container>
);
}
I have a React button that is a form and I intend to submit the form when I click on the Button. Unfortunately, when I click on the button, nothing happens and the page only reloads. Even when I just try to output to the console nothing happens but when you check the network, you could see an action being performed.
Below is my code which is just a simple login form and a functionality that validates user input. I need the button to call the function handleSubmit when I click on the button.
export default function Signin() {
const classes = useStyles();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [usernameError, setUsernameError] = useState('');
const [passwordError, setPasswordError] = useState('');
const validateUsername = () => {
setUsernameError(username.length > 3 ? null : 'Username must be longer than 3 characters')
}
const validatePassword = () => {
setPasswordError(password.length > 7 ? null : 'Password must be longer than 8 characters')
}
const handleSubmit = () => {
//const { history } = this.props;
console.log('testing button')
}
return (
<Grid
className={classes.root}
component="main"
container
>
<CssBaseline />
<Grid
className={classes.image}
item
md={4}
sm={7}
xs={false}
/>
<Grid
component={Paper}
elevation={6}
item
md={8}
sm={5}
square
xs={12}
>
<MuiThemeProvider theme={theme}>
<div className={classes.paper}>
<img
alt="logo"
src={process.env.PUBLIC_URL + '/images/....'}
/>
<Typography
component="h1"
style={{ color: '#E60000' }}
variant="h5"
>
Sign In
</Typography>
<form
className={classes.form}
noValidate
>
<Grid
container
spacing={2}
>
<Grid
item
xs={3}
/>
<Grid
item
xs={6}
>
<TextField
autoComplete="username"
className={`form-control ${usernameError ? 'is-invalid' : ''}`}
fullWidth
id="username"
label="Enter Username"
margin="normal"
name="username"
onBlur={validateUsername}
onChange={e => setUsername(e.target.value)}
required
value={username}
variant="outlined"
/>
<div className={classes.invalidFeedback}>{usernameError}</div>
</Grid>
<Grid
item
xs={3}
/>
<Grid
item
xs={3}
/>
<Grid
item
xs={6}
>
<TextField
autoComplete="current-password"
className={`form-control ${passwordError ? 'is-invalid' : ''}`}
fullWidth
id="password"
label="Password"
margin="normal"
name="password"
onBlur={validatePassword}
onChange={e => setPassword(e.target.value)}
required
type="password"
value={password}
variant="outlined"
/>
<div className={classes.invalidFeedback}>{passwordError}</div>
</Grid>
<Grid
item
xs={3}
/>
<Grid
item
xs={3}
/>
<Grid
item
xs={3}
>
<Button
className={classes.submit}
color="primary"
fullWidth
onClick={handleSubmit}
type="submit"
variant="contained"
>
Sign In
</Button>
<Grid
item
xs={3}
/>
</Grid>
</Grid>
<Grid container>
<Grid
item
xs={3}
/>
<Grid
item
xs={3}
>
<Link
className={classes.link}
to={`${process.env.PUBLIC_URL}/passwordreset`}
variant="body2"
>
<Button
className={classes.submit}
color="primary"
fullWidth
type="submit"
variant="text"
>
Forgot Password
</Button>
</Link>
</Grid>
<Grid item>
<Link
className={classes.link}
to={`${process.env.PUBLIC_URL}/signup`}
variant="body2"
>
<Button
className={classes.submit}
color="primary"
fullWidth
type="submit"
variant="text"
>
New User?
</Button>
</Link>
</Grid>
</Grid>
<Box mt={5}>
<SigninTrouble />
</Box>
</form>
</div>
</MuiThemeProvider>
</Grid>
</Grid>
);
}
Since you are using Form you need to handle submit method in form instead of your button. Because your button type is submit which triggers the onSubmit event in form.
<form onSubmit={handleSubmit}>
<button type="submit"></button>
</form>
If you want to make an async call you need to stop normal event cycle for your form.
const handleSubmit = (event) => {
// stop redirect
event.preventDefault();
console.log('testing button');
// here you can make your async call
}
In order to use a button with type submit it has to be nested within an html form tag and handle the submission with the onsubmit attribute.
Onother option is to attack an onClick event handler to your button and have your submission logic there.
Here is very simple example:
import React, {useEffect, useState} from 'react';
function Example(props) {
function clickHandler() {
alert('hi');
}
return (
<div>
<button onClick={clickHandler}>Click here</button>
</div>
);
}
export default Example;