I am now following this youtube video to develop an Instagram clone app by using React with firebase.
The error occurred at the point below, on the video at 2:36:29.
It says "Syntax error: Unexpected token (93:12)"
{user?.displayName ? (
<ImageUpload username={user.displayName} />
) : (
<h3>sorry you need to login to upload</h3>
)}
what I tried
・Just put <ImageUpload username={user.displayName} />
=> I got 「firebase is not defined」 error on the other js file.
・put "user.displayName" instead of "user?.displayName" (? is erased)
=> more complicated error occur that "TypeError: Cannot read properties of null (reading 'displayName')"
・Put {user ? (<ImageUpload username={user.displayName} />) : (<h3>Sorry you need to login !!</h3>)} eraced displayName
=> only visual works(surely, the username is not given in this case)
Adobe three tries, I guess displayName is the main point to solve the issue...
If you are good at React.js or you have seen the same error, please give me advice.
Whole App.js codes↓
App.js
import React, { useState, useEffect } from 'react'
import './App.css';
import Post from './Post';
import { db, auth } from './firebase';
import Modal from '#mui/material/Modal';
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import Input from '#mui/material/Input';
//import Typography from '#mui/material/Typography';
import ImageUpload from './ImageUpload';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
function App() {
const [posts, setPosts] = useState([]);
const [open, setOpen] = React.useState(false);
const [openSignIn, setOpenSignIn] = useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, setUser] = useState(null);
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((authUser) => {
if (authUser) {
//User has logged IN
console.log(authUser);
setUser(authUser);
//↑ is keep user logged in after refresh
} else {
//User has logged OUT
setUser(null);
}
})
return () => {
//perform some cleanup actions
unsubscribe(null);
}
}, [user, username]);
//useEffect => where the code runs, last []) means the code runs only once
useEffect(() => {
db.collection('posts').onSnapshot(snapshot => {
setPosts(snapshot.docs.map(doc => ({
id: doc.id,
post: doc.data()
})));
})
}, []);
//signup func
const signup = (event) => {
event.preventDefault();
auth
.createUserWithEmailAndPassword(email, password)
.then((authUser) => {
return authUser.user.updateProfile({
displayName: username
})
})
.catch((error) => alert(error.message));
setOpen(false);
}
//signin func
const signin = (event) => {
event.preventDefault();
auth
.signInWithEmailAndPassword(email, password)
.catch((error) => alert(error.message));
setOpenSignIn(false);
}
return (
<div className="app">
{user.displayName ? (
<ImageUpload username={user.displayName} />
) : (
<h3>sorry you need to login to upload</h3>
)}
<div className="app__header">
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="HeaderImage"
/>
{user ? (
<Button onClick={() => auth.signOut()}>Logout</Button>
) : (
<div className="app__loginContainer">
<Button onClick={() => setOpenSignIn(true)}>SignIn</Button>
<Button onClick={() => setOpen(true)}>SignUp</Button>
</div>
)}
</div>
<Modal
open={open}
onClose={() => setOpen(false)}
>
<Box sx={style}>
<form className="app__signup">
<center>
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="HeaderImage"
/>
</center>
<Input
type="text"
placeholder="username"
//at first, ↓ was value={username}, but typing cannot be shown on the screen in that case,
//https://stackoverflow.com/questions/34006333/cant-type-in-react-input-text-field
//↑is the trouble shooting, which says try defaultValue instead of value(V is capital).
defaultValue={username}
onChange={(e) => setUsername(e.target.value)}
/>
<Input
type="text"
placeholder="email"
defaultValue={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Input
type="text"
placeholder="password"
defaultValue={password}
onChange={(e) => setPassword(e.target.value)}
/>
<center>
<Button type="submit" onClick={signup}>SignUp</Button>
</center>
</form>
</Box>
</Modal>
<Modal
//signupModal
open={openSignIn}
onClose={() => setOpenSignIn(false)}
>
<Box sx={style}>
<form className="app__signup">
<center>
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="HeaderImage"
/>
</center>
<Input
type="text"
placeholder="email"
defaultValue={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Input
type="text"
placeholder="password"
defaultValue={password}
onChange={(e) => setPassword(e.target.value)}
/>
<center>
<Button type="submit" onClick={signin}>SignIn</Button>
</center>
</form>
</Box>
</Modal>
<h1>TEST</h1>
{/* header */}
{
posts.map(({ id, post }) => (
<Post username={post.username} caption={post.caption} imageUrl={post.imageUrl} />
))
}
{/* post */}
{/* post */}
</div >
);
}
export default App;
Here↓ is ImageUpload.js which I got firebase is not defined when I erase the? mark from ImageUpload tag,,,,
firebase is not defined from this line↓
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
ImageUpload.js
import React, { useState } from 'react';
import Button from '#mui/material/Button';
import { storage, db } from "./firebase";
import firebase from 'firebase/app';
function ImageUpload(username) {
const [image, setImage] = useState(null);
const [url, setUrl] = useState("");
const [progress, setProgress] = useState(0);
const [caption, setCaption] = useState('');
const handleChange = (e) => {
if (e.target.files[0]) {
setImage(e.target.files[0])
}
};
const handleUpload = () => {
const uploadTask = storage.ref('images/${image.name}').put(image);
uploadTask.on(
"state_change",
(snapshot) => {
//progress function
const progress = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(progress);
},
(error) => {
//error function
console.log(error);
alert(error.message);
},
() => {
//complete func
storage
.ref("images")
.child(image.name)
.getDownloadURL()
.then(url => {
//post image inside DB
db.collection("posts").add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
caption: caption,
imageUrl: url,
username: username
});
setProgress(0);
setCaption("");
setImage(null);
})
}
)
}
return (
<div>
{/* I want to have .... */}
{/* caption input */}
{/* file picker */}
{/* Post button */}
<progress value={progress} max="100" />
<input type="text" placeholder="enter a caption.." onChange={event => setCaption(event.target.value)} />
<input type="file" onChange={handleChange} />
<Button onClick={handleUpload}>
upload
</Button>
</div >
)
}
export default ImageUpload
To be safe here ↓ is firebase.js(privacy info are shown as ***)
firebase.js
import firebase from "firebase";
const firebaseApp = firebase.initializeApp({
apiKey: "***",
authDomain: "***.firebaseapp.com",
projectId: "***",
storageBucket: "***.appspot.com",
messagingSenderId: "*****",
appId: "****",
measurementId: "****"
})
const db = firebase.firestore();
const auth = firebase.auth();
const storage = firebase.storage();
export { db, auth, storage };
And index.js
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Moreover, firebase version is 8.10.0, using MacBook air intel one OS BigSur
Related
I am still learning react and I am building an app with MERN Stack. I tried submitting a post from the form, which is supposed to send data to the MongoDB Atlas database and also render the post on the page. But no data is sent to the database, nor is it rendered on the page. I don't really know where the problem is coming from, but I am having an axios error and a 404 error on the Chrome browser console. I don't know if Axios is not connected to the backend or if there is a problem with my codes.
Form.js
import React, { useState, useEffect } from 'react';
import { TextField, Button, Typography, Paper } from '#material-ui/core';
import FileBase from 'react-file-base64';
import { useDispatch, useSelector } from 'react-redux';
import useStyles from './styles';
import { createPost, updatePost } from '../../actions/posts';
//GET POST CUURENT ID
const Form = ({ currentId, setCurrentId }) => {
const [postData, setPostData] = useState({creator: '', title: '', message: '', tags: '', selectedFile: ''});
const post = useSelector((state) => currentId ? state.posts.find((p) => p._id === currentId) : null);
const classes = useStyles();
const dispatch = useDispatch();
useEffect(() => {
if(post) setPostData(post);
}, [post])
const handleSubmit = (e) => {
e.preventDefault();
if(currentId) {
dispatch(updatePost(currentId, postData));
} else {
dispatch(createPost(postData));
}
clear();
}
const clear = () => {
setCurrentId(null);
setPostData({creator: '', title: '', message: '', tags: '', selectedFile: ''});
}
return (
<Paper className={classes.paper}>
<form autoComplete='off' noValidate className={`${classes.root} ${classes.form}`} onSubmit={handleSubmit}>
<Typography variant='h6'>{ currentId ? 'Edit' : 'Create' } Your Expressions</Typography>
<TextField name='creator' variant='outlined' label='Creator' fullWidth value={postData.creator} onChange={(e) => setPostData({ ...postData, creator: e.target.value })} />
<TextField name='title' variant='outlined' label='Title' fullWidth value={postData.title} onChange={(e) => setPostData({ ...postData, title: e.target.value })} />
<TextField name='message' variant='outlined' label='Message' fullWidth value={postData.message} onChange={(e) => setPostData({ ...postData, message: e.target.value })} />
<TextField name='tags' variant='outlined' label='Tags' fullWidth value={postData.tags} onChange={(e) => setPostData({ ...postData, tags: e.target.value })} />
<div className={classes.fileInput}><FileBase type="file"multiple={false} onDone={({base64}) => setPostData({ ...postData, selectedFile: base64 })} />
</div>
<Button className={classes.buttonSubmit} variant='contained' color='primary' size='large' type='submit' fullWidth>Submit</Button>
<Button variant='outlined' color='primary' size='large' onClick={clear} fullWidth>Clear</Button>
</form>
</Paper>
);
}
export default Form;
Server/index.js
import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import cors from 'cors';
import postRoutes from './routes/posts.js'
const app = express();
app.use('/posts', postRoutes);
app.use(bodyParser.json({ limit: "30mb", extended: true}));
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true}));
app.use(cors());
app.use('/posts', postRoutes);
const CONNECTION_URL = 'mongodb+srv://Akan-
modanwealth:aakkaann#cluster0.jvfdwah.mongodb.net/?retryWrites=true&w=majority';
const PORT = process.env.PORT || 5000;
mongoose.connect(CONNECTION_URL).then(()=>{console.log('...')})
.then(() => app.listen(PORT, () => console.log('Server running on port:
${PORT}')))
.catch((error) => console.log(error.message));
App.js
import React, { useState, useEffect } from 'react';
import { Container, AppBar, Typography, Grow, Grid } from '#material-ui/core';
import { useDispatch } from 'react-redux';
import { getPosts } from './actions/posts';
import Posts from './components/Posts/Posts';
import Form from './components/Form/Form';
import expressions from './images/expressions.jpg';
import useStyles from './styles';
const App = () => {
const [currentId, setCurrentId] = useState(null);
const classes = useStyles();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPosts);
}, [currentId, dispatch]);
return (
<Container maxWidth="lg">
<AppBar className={classes.appBar} position="static" >
<Typography className={classes.heading} variant="h2" align="center">Expressions</Typography>
<img className={classes.image} src={expressions} alt="expressions" height="80" width="60" />
</AppBar>
<Grow in>
<Container>
<Grid container justifyContent="space-between" alignItems="stretch" spacing={3}>
<Grid item xs={12} sm={7}>
<Posts setCurrentId={setCurrentId} />
</Grid>
<Grid item xs={12} sm={4}>
<Form currentId={currentId} setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Container>
</Grow>
</Container>
);
}
export default App;
api/index.js
import axios from 'axios';
const url = 'http://localhost:5000/posts';
export const fetchPosts = () => axios.get(url);
export const createPost = (newPost) => axios.post(url, newPost);
export const updatePost = (id, updatedPost) => axios.patch(`${url}/${id}`,
updatedPost);
routes/posts.js
import express from 'express';
import { getPosts, createPost, updatePost} from
'../controllers/posts.js';
const router = express.Router();
router.get('/', getPosts);
router.get('/', createPost);
router.patch('/:id', updatePost)
export default router;
Here is the error on the browser console
So there are a couple of things. First, you may have exposed your password in your MongoDB URI, so I'd go and change that immediately. Second, is there a reason you're running app.use("/posts", postRoutes); twice?
Lastly, it looks like you're posting to /posts, but you're not specifying a route after that. You didn't share your routes, but from the looks of it /posts uses all routes in your routes folder. You need to give a specific route, like /posts/create or something. Otherwise you're just saying making a POST request to the object with all your middleware and node.js doesn't know which middleware to use.
I've written the code to filter the post in the useEffect. I can't find a way to implement it. I already have 5 posts in my database. I'm bringing all 5 posts using useSelector but I can't find a way to filter while I am typing in the search bar. If I try to set the filtered value in the setListsPosts2(filteredPostList) when fetching those data using the map I didn't get my all posts.
when I do const [listPosts2, setListPosts2] = useState([posts]); it started continues loop and giving error also as asking me add posts in the lists of useEffect dependencies but when i add it it started continues loop of error
here is my homepage.js file
import { useEffect, useState } from 'react';
import { Col, Container, Form, Row } from 'react-bootstrap';
import { ToastContainer } from 'react-toastify';
import { useDispatch, useSelector } from 'react-redux';
import { listPosts } from '../actions/postActions';
import Banner from '../components/Banner';
import Post from '../components/Post';
import Paginate from '../components/Paginate';
const HomePage = ({ match }) => {
const [keyword, setKeyword] = useState('');
const [listPosts2, setListPosts2] = useState([]);
const pageNumber = match.params.pageNumber || 1;
const dispatch = useDispatch();
const postLists = useSelector((state) => state.postLists);
const { posts, pages, page } = postLists;
const postCreate = useSelector((state) => state.postCreate);
const { success: successCreate } = postCreate;
const postUpdate = useSelector((state) => state.postUpdate);
const { success: successUpdate } = postUpdate;
const postDelete = useSelector((state) => state.postDelete);
const { success: deleteSuccess } = postDelete;
useEffect(() => {
const filteredPostList = posts?.filter((post) =>
post.title.toLowerCase().includes(keyword.toLowerCase())
);
setListPosts2(filteredPostList);
dispatch(listPosts(pageNumber));
}, [dispatch, pageNumber, deleteSuccess, successCreate, successUpdate]);
return (
<div>
<ToastContainer />
<Banner />
<div className="my-3">
<Container id="posts">
<Form className="searchBoxForm">
<Form.Control
type="text"
name="q"
onChange={(e) => setKeyword(e.target.value)}
placeholder="Search Posts..."></Form.Control>
</Form>
<h2 className="mt-3" style={{ letterSpacing: '4px' }}>
POSTS
</h2>
<Row className="mt-3">
<Col>
<Row>
{posts
?.map((post) => (
<Col key={post._id} md={3} sm={4}>
<Post post={post} />
</Col>
))
.sort()
.reverse()}
</Row>
<Paginate pages={pages} page={page} />
</Col>
</Row>
</Container>
</div>
</div>
);
};
export default HomePage;
Hey I have tried a lot of things but I can't seem to get this thing to work I am trying to make a simple modal using material UI but whenever I try to change state it's showing me a blank white page. does anyone have any idea why is it happening here's my code
a
import {Button,Modal} from "#material-ui/core";
import {useState} from "react";
import RegisterBody from '../Register/RegisterForm'
import LoginBody from '../Login/LoginForm'
const UserModel = () => {
const [isOpen, setIsOpen] = useState(false)
const [isLoginModel, setLoginModel] = useState();
const [MainModelBody] = useState(LoginBody);
function handleRegister() {
if (!isLoginModel) {
console.log("Register")
//Todo: Send Register Request
} else {
MainModelBody.setState(RegisterBody)
setLoginModel(false)
}
}
function handleSignIn() {
if (isLoginModel) {
console.log("Login")
//Todo: send Sign in request
} else {
MainModelBody.setState(LoginBody)
setLoginModel(true)
}
}
function handleUserModel() {
setIsOpen(!isOpen)
}
return (
<>
<Button className="userActionButton" onClick={handleUserModel}>Sign In</Button>
<Modal open={isOpen}
onClose={!isOpen}
disablePortal
disableEnforceFocus
disableAutoFocus
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
>
<div className = 'UserModel'>
<LoginBody/>
<Button onClick={handleRegister}>Register</Button>
<Button onClick={handleSignIn}>Sign In</Button>
</div>
</Modal>
</>
);
}
export default UserModel
LoginBody
import {useState} from 'react';
import LoginElements from './LoginElements';
import {FormControl} from "#material-ui/core";
const LoginForm = ()=> {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSubmit = (e) => {
e.preventDefault();
const user = {email, password}
console.log(user)
};
return (
<div className="form">
<FormControl noValidate autoComplete="off" onSubmit={handleSubmit}>
<LoginElements
email={email}
password={password}
setEmail={setEmail}
setPassword={setPassword}
/>
</FormControl>
</div>
);
}
export default LoginForm;
LoginElements
import {Button, TextField} from "#material-ui/core";
const LoginElements = (props) => {
return (
<>
<TextField label="Email" type="email" required value={props.email} onChange={(e) => props.setEmail(e.target.value)}/>
<br/>
<TextField label="Password" type="password" required value={props.password} onChange={(e) => props.setPassword(e.target.value)}/>
<br/>
<Button variant="contained" type="submit">Login</Button>
<Button variant="contained" type="register">Register</Button>
<br/>
<label>{props.email}</label>
<label>{props.password}</label>
</>
)
}
export default LoginElements;
RegisterBody
import {useState} from 'react';
import RegisterElements from './RegisterElements';
const LoginForm = ()=> {
const [email, setEmail] = useState('')
const [confirmEmail, setConfirmEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const handleSubmit = (e) => {
e.preventDefault();
const user = {email, password}
console.log(user)
};
return (
<div className="form">
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<RegisterElements
email={email}
confirmEmail={email}
password={password}
confirmPassword={password}
setEmail={setEmail}
setConfirmEmail={setEmail}
setPassword={setPassword}
setConfirmPassword={setPassword}
/>
</form>
</div>
);
}
export default LoginForm;
Register Elements
import {Button, TextField} from "#material-ui/core";
const RegisterElements = (props) => {
return (
<>
<TextField label="Confirm Email" type="email" required value={props.email}
onChange={(e) => props.setEmail(e.target.value)}/>
<TextField label="Confirm Email" type="email" required value={props.confirmEmail}
onChange={(e) => props.setConfirmEmail(e.target.value)}/>
<br/>
<TextField label="Password"
type="password"
required value={props.password}
onChange={(e) => props.setPassword(e.target.value)}/>
<TextField label="Confirm Password" required value={props.confirmPassword}
onChange={(e) => props.setConfirmPassword(e.target.value)}/>
<br/>
<Button variant="contained" type="Login">Login</Button>
<Button variant="contained" type="submit">Login</Button>
<label>{props.email}</label>
<label>{props.password}</label>
</>
)
}
export default RegisterElements;
My apologies for bad code i am new with react
You are "toggling" the isLoginModel state but you only render LoginBody in the JSX.
You should be able to use the isLoginModel state and conditionally render either the LoginBody or RegisterBody component into the modal body. There's really no need for the extra state to hold a component reference.
import {Button,Modal} from "#material-ui/core";
import {useState} from "react";
import RegisterBody from '../Register/RegisterForm'
import LoginBody from '../Login/LoginForm'
const UserModel = () => {
const [isOpen, setIsOpen] = useState(false)
const [isLoginModel, setLoginModel] = useState(true); // login by default
function handleRegister() {
if (!isLoginModel) {
console.log("Register");
// TODO: Send Register Request
} else {
setLoginModel(false);
}
}
function handleSignIn() {
if (isLoginModel) {
console.log("Login");
// TODO: send Sign in request
} else {
setLoginModel(true);
}
}
function handleUserModel() {
setIsOpen(isOpen => !isOpen);
}
return (
<>
<Button className="userActionButton" onClick={handleUserModel}>Sign In</Button>
<Modal open={isOpen}
onClose={!isOpen}
disablePortal
disableEnforceFocus
disableAutoFocus
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
>
<div className='UserModel'>
{isLoginModel ? <LoginBody /> : <RegisterBody />} // <-- condition render
<Button onClick={handleRegister}>Register</Button>
<Button onClick={handleSignIn}>Sign In</Button>
</div>
</Modal>
</>
);
}
I'm starting to learn React and following the tutorial and got stuck with this error when I was trying to upload picture. When I press upload button, this error "Objects are not valid as a React child (found: object with keys {username}). If you meant to render a collection of children, use an array instead." shown up and I couldn't reload the page anymore.
Render Error
Here are the codes:
1.App.js
import React, { useEffect, useState } from "react";
import './App.css';
import Post from './Post';
import { auth, db } from "./firebase";
import Modal from '#material-ui/core/Modal';
import { makeStyles } from '#material-ui/core/styles';
import { Button, Input } from "#material-ui/core";
import ImageUpload from './ImageUpload';
function getModalStyle() {
const top = 50;
const left = 50;
return {
top: `${top}%`,
left: `${left}%`,
transform: `translate(-${top}%, -${left}%)`,
};
}
const useStyles = makeStyles((theme) => ({
paper: {
position: 'absolute',
width: 400,
backgroundColor: theme.palette.background.paper,
border: '2px solid #000',
boxShadow: theme.shadows[5],
padding: theme.spacing(2, 4, 3),
},
}));
function App() {
const classes = useStyles();
const [modalStyle] = React.useState(getModalStyle);
const [posts, setPosts] = useState([]);
const [open, setOpen] = useState(false);
const [openSignIn, setOpenSignIn] = useState('');
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, setUser] = useState(null);
//UseEffect -> Run a piece of code based on a specific condition
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((authUser) => {
if (authUser) {
//user has logged in...
console.log(authUser);
setUser(authUser);
} else {
//user has logged out...
setUser(null);
}
return () => {
//perform some cleanup action
unsubscribe();
}
})
}, [user, username]);
useEffect(() => {
//this is where the code runs
db.collection('posts').onSnapshot(snapshot => {
//everytime a new post is added, this code fires...
setPosts(snapshot.docs.map(doc => ({
id: doc.id,
post: doc.data()
})));
})
}, []);
const signUp = (event) => {
event.preventDefault();
auth
.createUserWithEmailAndPassword(email, password)
.then((authUser) => {
return authUser.user.updateProfile({
displayName: username
})
})
.catch((error) => alert(error.message))
}
const signIn = (event) => {
event.preventDefault();
auth
.signInWithEmailAndPassword(email, password)
.catch((error) => alert(error.message))
setOpenSignIn(false);
}
return (
<div className="app">
{user?.displayName ? (
<ImageUpload username={user.displayName} />
) : (
<h3>Sorry you need to login to upload</h3>
)}
<Modal
open={open}
onClose={() => setOpen(false)}
>
<div style={modalStyle} className={classes.paper}>
<form className="app__signup">
<center>
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt=""
/>
</center>
<Input
placeholder="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<Input
placeholder="email"
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Input
placeholder="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button type="submit" onClick={signUp}>Sign Up</Button>
</form>
</div>
</Modal>
<Modal
open={openSignIn}
onClose={() => setOpenSignIn(false)}
>
<div style={modalStyle} className={classes.paper}>
<form className="app__signup">
<center>
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt=""
/>
</center>
<Input
placeholder="email"
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Input
placeholder="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button type="submit" onClick={signIn}>Sign In</Button>
</form>
</div>
</Modal>
<div className="app__header">
<img
className="app__headerImage"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="" />
</div>
{user ? (
<Button onClick={() => auth.signOut()}>Logout</Button>
) : (
<div className="app__loginContainer">
{/* : is stand for OR */}
<Button onClick={() => setOpenSignIn(true)}>Sign In</Button>
<Button onClick={() => setOpen(true)}>Sign Up</Button>
</div>
)}
<h1>Hello Joes! Let's build an Instagram CLone with React</h1>
{
posts.map(({ id, post }) => (
<Post key={id} username={post.username} caption={post.caption} imgUrl={post.imgUrl} />
))
}
</div>
);
}
export default App;
Here is the ImageUpload file
2. ImageUpload.js
import { Button } from '#material-ui/core'
import React, { useState } from 'react';
import { storage, db } from './firebase';
import firebase from "firebase";
function ImageUpload(username) {
const [image, setImage] = useState(null);
const [progress, setProgress] = useState(0);
const [caption, setCaption] = useState('');
const handleChange = (e) => {
if (e.target.files[0]) {
setImage(e.target.files[0]);
}
};
const handleUpload = () => {
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on(
"state_change",
(snapshot) => {
//progress funtion...
const progress = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(progress);
},
(error) => {
//Error function...
console.log(error);
alert(error.message);
},
() => {
// Complete function...
storage
.ref("images")
.child(image.name)
.getDownloadURL()
.then(url => {
// Post image on db
db.collection("posts").add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
caption: caption,
imageUrl: url,
username: username
});
setProgress(0);
setCaption("");
setImage(null);
});
}
);
};
return (
<div>
{/* I want to have... */}
{/* Caption input */}
{/* File picker */}
{/* Post button */}
<progress value={progress} max="100" />
<input type="text" placeholder="Enter a caption..." onChange={event => setCaption(event.target.value)} value={caption} />
<input type="file" onChange={handleChange} />
<Button onClick={handleUpload}>
Upload
</Button>
</div>
)
}
export default ImageUpload
Thanks guys!
This line is wrong:
<progress value={progress} max="100" />
React components have to be upper case.
Your progress is a number, not a React component
You probably wanted to import the component Progress and write:
<Progress value={progress} max="100" />
I'm not great at testing, and new to Jest and Enzyme. I have a Login component that consists of two TextInput components for username and password and a Button component. I am testing each component individually.
I would just like to test that a username and password was returned by onLogin.
Here is the component:
export const onLogin = (user, password) => {
console.log('User', user, 'Password', password)
return [user, password];
};
function Login() {
const [user, setUser] = useState("");
const [password, setPassword] = useState("");
return (
<LoginWrapper>
<Branding brand={brand.brandName} />
<FormWrapper onSubmit={(e) => { e.preventDefault(); onLogin(user, password) }}>
<Stack>
<TextInput
className="username"
type="text"
label="Username"
onChange={e => setUser(e.target.value)}
/>
</Stack>
<Stack>
<TextInput
className="password"
type="password"
label="Password"
onChange={e => {setPassword(e.target.value); console.log('user', user)}}
/>
</Stack>
<Stack padding="0" align="right">
<Button type="submit">Login</Button>
</Stack>
</FormWrapper>
</LoginWrapper>
);
}
export default Login;
My test:
describe("<Login />", () => {
it("renders text input correctly", () => {
const tree = renderer.create(<ThemeProvider theme={themes.default}><Login /></ThemeProvider>).toJSON();
expect(tree).toMatchSnapshot();
});
it("calls onLogin when button clicked", () => {
const onSubmitMock = jest.fn();
const component = Enzyme.mount(
<ThemeProvider theme={themes.default}><Login onSubmit={onSubmitMock} /></ThemeProvider>
);
component.find("input.username").simulate('change', { target: { value: 'myUser' } })
component.find("input.password").simulate('change', { target: { value: 'myPassword' } })
component.find("form").simulate("submit");
console.log("onClickMock.mock", onSubmitMock.mock)
expect(onSubmitMock).toBeCalled()
});
});
Results:
Expected mock function to have been called, but it was not called.
Your testing approach is correct except for:
In your test, you are mocking a callback function and passing it as a property onSubmit to your component. Then you need to call this function from your component when you submit the form.
Instead, you are calling the onLogin function on your component that does not have any
repercussion.
In order to fix this, declare the properties on your component function as a parameter, and call props.onSubmit on your form submit.
function Login(props) {
const [user, setUser] = useState("");
const [password, setPassword] = useState("");
return (
<LoginWrapper>
<Branding brand={brand.brandName} />
<FormWrapper onSubmit={(e) => { e.preventDefault(); props.onSubmit(user, password) }}>
<Stack>
<TextInput
className="username"
type="text"
label="Username"
onChange={(e) => setUser(e.target.value)}
/>
</Stack>
<Stack>
<TextInput
className="password"
type="password"
label="Password"
onChange={(e) => { setPassword(e.target.value) }}
/>
</Stack>
<Stack padding="0" align="right">
<Button type="submit">Login</Button>
</Stack>
</FormWrapper>
</LoginWrapper>
);
}