I have a single page application where I'm trying to create a separate login page which would eventually redirect the authenticated user to the main application but my submitFormHandler is not getting invoked. The point of authentication is not for access to the main site(App.jsx) but instead for visibility of the NavMenu.
When I had the LoginForm and Login component in App.jsx all was working but it was still in the form of a SPA which wasn't what I was wanting. I moved things around and found that rendering the login and default site(App) with a in the DOM did what I wanted, but now I have this current issue.
Just to get things clear, I'm a complete novice in React and have never tried routing directly in the DOM.
My code:
index.js:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Login from "./components/Login";
import LoginForm from "./components/LoginForm";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import axios from "axios";
import "./index.css"
let apiUrl;
if (process.env.NODE_ENV === "production") {
apiUrl = "https://xxxxxxxx.herokuapp.com/api/v1";
} else {
apiUrl = "http://localhost:3000/api/v1";
}
axios.defaults.baseURL = apiUrl;
ReactDOM.render((
<BrowserRouter>
<Switch>
<Route exact path="/" component={App} />
<Route
exact path="/login"
render={(props) =>
<div>
<Login />
</div>
}
/>
</Switch>
</BrowserRouter>
), document.getElementById("root"));
reportWebVitals();
Login.jsx:
import React, { Component } from 'react';
import { authenticate } from '../modules/auth';
import LoginForm from "./LoginForm";
class Login extends Component {
state = {
renderLoginForm: false,
authenticated: false,
message: ""
}
onChangeHandler = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
onLogin = async (e) => {
e.preventDefault();
const response = await authenticate(
e.target.email.value,
e.target.password.value
);
if (response.authenticated) {
this.setState({ authenticated: true });
} else {
this.setState({ message: response.message, renderLoginForm: false });
}
};
render() {
const { renderLoginForm, authenticated, message } = this.state;
let renderLogin;
// eslint-disable-next-line default-case
switch (true) {
case renderLogin && !authenticated:
renderLogin = <LoginForm submitFormHandler={this.onLogin} />;
break;
case !renderLoginForm && !authenticated:
renderLogin = (
<>
<button
id="login-button"
onClick={() => this.setState({ renderLoginForm: true })}
>
Login
</button>
<p id="message">{message}</p>
</>
);
break;
case authenticated:
renderLogin = (
<p id="welcome-message">
You are logged in as{" "}
{JSON.parse(sessionStorage.getItem("credentials")).uid}.
</p>
);
break;
}
return (
<>
{renderLogin}
</>
)
}
}
export default Login;
LoginForm.jsx:
import React, { useState } from "react";
import { Link, BrowserRouter } from "react-router-dom";
import { Button, Form, Container, Message, MenuItem } from "semantic-ui-react";
const LoginForm = ({ submitFormHandler }) => {
const [message, setMessage] = useState();
return (
<>
<Container>
<Form onSubmit={submitFormHandler} id="login-form">
<Form.Input
icon="user"
iconPosition="left"
placeholder="email"
label="Email:"
type="email"
name="email"
id="login-email"
required
/>
<Form.Input
icon="lock"
iconPosition="left"
placeholder="password"
label="Password:"
type="password"
name="password"
id="login-password"
required
/>
<Button id="login-submit" type="submit" content="Submit" primary />
</Form>
</Container>
<Container>
<div>
<BrowserRouter>
<Link to="/register" id="register">
Don't have an account yet? Sign up now!
</Link>
</BrowserRouter>
</div>
{message && (
<Message id="onlogin-message" color="red">
{message}
</Message>
)}
</Container>
</>
);
};
export default LoginForm;
App.jsx:
/* eslint-disable default-case */
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
// Component Imports
import Header from "./components/Header";
import Footer from "./components/Footer";
import SideBar from "./components/SideBar";
import LoginForm from "./components/LoginForm";
import Dashboard from "./components/Dashboard";
import Preferences from "./components/Preferences";
import DisplayWizard from "./components/DisplayWizard";
// import InputFields from "./components/InputFields";
// Module Imports
import { authenticate } from "./modules/auth";
// Icon Imports
import AppsIcon from "#material-ui/icons/Apps";
import HomeIcon from "#material-ui/icons/Home";
import StoreIcon from "#material-ui/icons/Store";
import CreateIcon from "#material-ui/icons/Create";
import DeleteIcon from "#material-ui/icons/Delete";
import VpnKeyIcon from "#material-ui/icons/VpnKey";
import HistoryIcon from "#material-ui/icons/History";
import SettingsIcon from "#material-ui/icons/Settings";
import DriveEtaIcon from "#material-ui/icons/DriveEta";
import MenuBookIcon from "#material-ui/icons/MenuBook";
import BusinessIcon from "#material-ui/icons/Business";
import LocalParkingIcon from "#material-ui/icons/LocalParking";
import FormatListBulletedIcon from "#material-ui/icons/FormatListBulleted";
import SupervisorAccountIcon from "#material-ui/icons/SupervisorAccount";
function onClick(e, item) {
window.alert(JSON.stringify(item, null, 2));
}
// Menu List Items
const items = [
{ name: "home", label: "Home", Icon: HomeIcon },
"divider",
{
name: "manage",
label: "Manage",
Icon: AppsIcon,
items: [
{ name: "my cars", label: "My Cars", Icon: DriveEtaIcon, onClick },
{ name: "inventory", label: "Inventory", Icon: StoreIcon, onClick },
{ name: "past orders", label: "Past Orders", Icon: HistoryIcon, onClick },
{
name: "parking spots",
label: "Parking Spots",
Icon: LocalParkingIcon,
onClick,
},
],
},
"divider",
{ name: "reports", label: "Reports", Icon: MenuBookIcon },
"divider",
{
name: "stages",
label: "Stages",
Icon: FormatListBulletedIcon,
items: [
{ name: "workshop", label: "Workshop", onClick },
{ name: "panelshop", label: "Panelshop", onClick },
],
},
"divider",
{
name: "admin",
label: "Admin",
Icon: SupervisorAccountIcon,
items: [
{
name: "create new login",
label: "Create new login",
Icon: VpnKeyIcon,
onClick,
},
{
name: "set company/dealership",
label: "Set Company/Dealership",
Icon: BusinessIcon,
onClick,
},
{ name: "edit flow", label: "Edit Flow", Icon: CreateIcon, onClick },
{
name: "delete previous order",
label: "Delete Previous Order",
Icon: DeleteIcon,
onClick,
},
{
name: "set default options",
label: "Set Default Options",
Icon: CreateIcon,
onClick,
},
],
},
"divider",
{
name: "settings",
label: "Settings",
Icon: SettingsIcon,
items: [
{ name: "profile", label: "Profile", onClick },
{ name: "preferences", label: "Preferences", onClick },
],
},
];
class App extends Component {
state = {
regnum: "",
ordernum: "",
make: "nissan",
model: "",
year: "",
color: "",
mileage: "",
// renderLoginForm: false,
// authenticated: false,
// message: "",
};
render() {
return (
<>
<div className="App" id="">
<div className="wrapper">
{/* {renderLogin} */}
</div>
<Header />
<DisplayWizard onChangeHandler={this.onChangeHandler} />
<SideBar items={items} />
<Footer />
</div>
</>
);
}
}
export default App;
If need be, I can upload the old code before I made the changes.
Thanks for any replies and help in advance, it is much appreciated :)
Alright the problem was just a typo:
case renderLogin && !authenticated:
Instead it should be:
case renderLoginForm && !authenticated:
I am learning to react but I am stuck in one issue. I am trying to get the array properties in my Useritem.js file
this is my User.js file
import React, { Component } from 'react'
import Useritems from './Components/Useritems';
const User = () => {
state = {
users: [
{ name: 'David', age: '20', Position: 'developer' },
{ name: 'Francis', age: '20', Position: 'Software Engineer' },
]
}
return (
<div>
{this.state.users.map(user => (
<Useritems user={user} />
))}
</div>
);
}
export default User
And this is my Useritem.js file
import React from 'react'
const Useritems = ({ user: { name, age, job } }) => {
return (
<div>
<h1>{name}</h1>
<h2>{age}</h2>
<h3>{job}</h3>
</div>
)
}
export default Useritems
But I am getting an error saying that the property name is not defined
You are using a functional component (as opposed to a class component), so you cannot use this.state. Instead you need to use the hook useState to handle your state, which you can do like this:
import React, { useState } from "react";
import Useritems from "./Components/Useritems";
const initialUsers = [
{ name: "David", age: "20", Position: "developer" },
{ name: "Francis", age: "20", Position: "Software Engineer" }
];
const Users = () => {
const [users, setUsers] = useState(initialUsers);
return (
<div>
{users.map((user) => (
<Useritems key={user.name} user={user} /> // don't forget the key, though will want to find something more unique than name!
))}
</div>
);
};
import React, { Component } from 'react';
import './App.css';
const list = [
{
title: 'React',
url: 'https://facebook.github.io/react/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 1,
},
];
class App extends Component {
state = {
list,
text: 'abc',
searchTerm: ''
}
onDisMiss = (id) => {
const updateList = this.state.list.filter((item) => item.objectID != id)
return () => this.setState({ list: updateList })
}
onSearchChange = (event) => {
this.setState({ searchTerm: event.target.value })
}
isSearched = (searchTerm) => {
return (item) => item.title.toLowerCase().includes(searchTerm.toLowerCase())
}
render() {
const { searchTerm, list } = this.state
return (
<div>
<Search value={searchTerm}
onChange={this.onSearchChange}>Search</Search>
<Table list={list} pattern={searchTerm} onDissMiss={this.onDisMiss} />
</div>
);
}
}
class Search extends Component {
render() {
const { value, onChange, children } = this.props
return (
<div>
<form>
{children}<input type="text" onChange={onChange} value={value} />
</form>
</div>
);
}
}
class Table extends Component {
render() {
const { list, pattern, onDisMiss } = this.props
return (
<div>
{list.filter(isSearched(pattern)).map(item =>
<div key={item.objectID}>
<span><a href={item.url}>{item.title}</a></span>
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span>
<span>
<button onClick={onDisMiss(item.objectID)} type="button">Dismiss</button>
</span>
</div>)
}
</div>
);
}
}
export default App;
Road to react Book The Table component related.I get undefined for the isSearched method. how can I fix it so it works correctly its from the book road to react it seems like the book has a few error which I have problems solving because am just learning react. can you help with the solution and why this problem is actually happening
You should put the isSearched method inside the Table class and not the App class
I am trying to pass a state array from one component into another, to share and display the data. So the data is from a rest api that gets saved into an array called saved[]. I am trying to pass this into another component to display my saved articles. I have a few issues:
1 - No data is being displayed in the other component
2 - When switching between routes I get this error:
warning: Can't perform a React state update on an unmounted component.
So my code so far is as follows:
newshero.js
import React, { Component } from 'react';
import './news-hero.css';
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
const responsive = {
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: 1,
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 1,
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 1,
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
},
};
class NewsHero extends Component {
state = {
loading: false,
data: [],
headline: [],
saved: []
}
saved = headline => {
this.setState(
(prevState) => ({ saved: [...prevState.saved, headline] }),
() => {
console.log('Saved articles = ', this.state.saved);
alert('Article saved');
localStorage.setItem('saved', JSON.stringify(this.state.saved));
localStorage.getItem('saved');
});
}
constructor(props) {
super(props)
this.saved = this.saved.bind(this)
}
onError() {
this.setState({
imageUrl: "../assets/img-error.jpg"
})
}
componentDidMount() {
this.setState({ loading: true, saved: localStorage.getItem('saved') ? JSON.parse(localStorage.getItem('saved')) : [] })
fetch('https://newsapi.org/v2/everything?q=timbaland&domains=rollingstone.com,billboard.com&excludeDomains=townsquare.media&apiKey=8')
.then(headline => headline.json())
.then(headline => this.setState({ headline: headline.articles, loading: false }, () => console.log(headline.articles)))
}
render() {
return (
<div className="hero">
<h2 className="text-left">News</h2>
{this.state.loading
? "loading..."
: <div>
<Carousel
additionalTransfrom={0}
showDots={true}
arrows={true}
autoPlaySpeed={3000}
autoPlay={false}
centerMode={false}
className="carousel-hero"
containerClass="container-with-dots"
dotListClass="dots"
draggable
focusOnSelect={false}
infinite
itemClass="carousel-top"
keyBoardControl
minimumTouchDrag={80}
renderButtonGroupOutside={false}
renderDotsOutside
responsive={responsive}>
{this.state.headline.map((post, indx) => {
return (
<div className="text-left mt-5" key={indx}>
<img className="media-img card-img-top card-img-hero" src={post.urlToImage} alt="Alt text"></img>
<div className="card-body container hero-text-body">
<h1 className="card-title hero-title text-truncate">{post.title}</h1>
<button className="btn-primary btn mt-2 mb-4" onClick={() => this.saved(post)}>Add this article</button>
<p className="card-text">{post.description}</p>
Read More
</div>
</div>
)
})}
</Carousel>
</div>
}
</div>
)
}
}
export default NewsHero;
main-news.js
import React, { Component } from 'react';
import '../news-main/news-main.css';
import News from '../news/news';
import NewsHero from '../news-hero/news-hero';
import Sports from '../sports/sports';
class NewsMain extends Component {
render() {
return (
<div>
<NewsHero />
<News />
<Sports />
</div>
)
}
}
export default NewsMain;
app.js
import React, { Component } from 'react';
// import logo from './logo.svg';
import './App.css';
import Header from './header/header';
import NewsMain from './news-main/news-main';
import Footer from './footer/footer';
import Home from './home/home';
import { Router } from '#reach/router';
class App extends Component {
constructor(props) {
super(props);
this.state = {saved: []};
}
render() {
return (
<div className="App">
<Header />
<div>
<Router>
<Home default path='/news' savedArticles={this.state.saved} />
<NewsMain path='/news' />
</Router>
</div>
<Footer title="Footer" />
</div>
)
}
}
export default App;
Trying to pass data into the below:
import React, { Component } from 'react';
import '../home/home.css';
class Home extends Component {
componentDidMount() {
this.setState({ loading: true, saved: localStorage.getItem('saved') ? JSON.parse(localStorage.getItem('saved')) : [] })
fetch('https://newsapi.org/v2/everything?q=timbaland&domains=rollingstone.com,billboard.com&excludeDomains=townsquare.media&apiKey=8')
.then(headline => headline.json())
.then(headline => this.setState({ headline: headline.articles, loading: false }, () => console.log('Saved articles', headline.articles)))
}
render() {
return (
<div className="mt-5 saved">
{this.props.savedArticles.map((article, indx) => {
return (
<div className="media mb-5" key={indx}>
<img className="media-img sports-thumb mr-3 mb-3 d-none d-sm-block" src={article.urlToImage} alt="Alt text"></img>
<div className="media-body text-left">
<h5 className="mt-0">{article.title}</h5>
<p className="text-left">{article.description}</p>
Read More
</div>
</div>
)
})}
</div>
)
}
}
export default Home;
Something to do with the state but I can't see where and why? Any idea's
Can somebody please help me in fixing this code.
I have created two files called app.js and searchbooks.js for the project. But I received these two reviews.
Below is app.js
import React from 'react'
// import * as BooksAPI from './BooksAPI'
import './App.css';
import * as BooksAPI from './BooksAPI';
// import Header from './components/Header';
import BookShelf from './Components/BookShelf';
import SearchBooks from './Components/SearchBooks';
import {Route} from 'react-router-dom';
class BooksApp extends React.Component {
state = {
books:[]
}
componentDidMount(){
BooksAPI.getAll().then(data=>{
this.setState({
books:data
})
})
}
bookShelfHandler =(book,shelf)=>{
BooksAPI.update(book,shelf)
BooksAPI.getAll().then(data=>{
this.setState({
books:data
})
})
}
render() {
return (
<div className="app">
{/* <Route exact path="/" render={()=>(
<Header/>
)}/> */}
<Route exact path="/" render={()=>(
<BookShelf books={this.state.books} bookShelfHandler = {this.bookShelfHandler}/>
)}/>
<Route path="/search" render={()=>(
<SearchBooks bookShelfHandler= {this.bookShelfHandler}
books={this.state.books}
/>
)}/>
</div>
)
}
}
export default BooksApp
This is the searchbook.js file
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import Book from './Book'
import NotFound from './NotFound'
import * as BooksAPI from '../Utils/BooksAPI'
import PropTypes from 'prop-types'
class SearchBooks extends Component {
static propTypes = {
myBooks: PropTypes.array.isRequired,
onBookUpdate: PropTypes.func.isRequired
}
state = {
query: '',
books: [],
error: ''
}
bookShelfHandler() {
return this.props.bookShelfHandler;
}
handleChange = (query) => {
this.setState({ query })
this.bookSearch(query)
}
changeBookShelf = (books) => {
let all_Books = this.props.myBooks
for (let book of books) {
book.shelf = "none"
}
for (let book of books) {
for (const b of all_Books) {
if (b.id === book.id) {
book.shelf = b.shelf
}
}
}
return books
}
bookSearch = (query) => {
if (query) {
BooksAPI.search(query, 10)
.then((books) => {
if (books.length) {
books = books.filter((book) => (book.imageLinks))
// books = this.changeBookShelf(books)
this.setState({ books, error: '' })
} else {
this.setState({ books: [], error: 'error' })
}
})
} else {
this.setState({ books: [], query: ''})
}
}
addBook = (book, shelf) => {
this.props.onBookUpdate(book, shelf)
}
render () {
return (
<div className='search-books'>
<div className='search-books-bar'>
<Link className='close-search' to='/'>Close</Link>
<div className='search-books-input-wrapper'>
<input type='text'
placeholder='Search by title or author'
value={this.state.query}
onChange={(e) => (this.handleChange(e.target.value))} />
</div>
</div>
<div className='search-books-results'>
<ol className='books-grid'>
{this.state.query &&
this.state.books.map((book) => (<Book bookShelfHandler={this.props.bookShelfHandler} book={book} key={book.id} onUpdate={(shelf) => (this.addBook(book, shelf))}/>))}
{
this.state.error && <NotFound />
}
</ol>
</div>
</div>
)
}
}
export default SearchBooks
I tried fixing the code but still stuck at some points. Please help me in fixing the errors, the project is made on react and have to be submitted in 8 hours.
See the picture above to know more about the errors.
As per the review and from the code,
In you app.js file you are passing props
<SearchBooks bookShelfHandler= {this.bookShelfHandler}
books={this.state.books}
/>
but the required props in you component is
myBooks: PropTypes.array.isRequired,
onBookUpdate: PropTypes.func.isRequired
it just you are passing the wrong prop names to the component,
to fix this just change the names in your app.js file to
<SearchBooks onBookUpdate= {this.bookShelfHandler}
myBooks={this.state.books}
/>