How to pass data to a component from sibling component react - javascript

My requirement is to re-render header component based on signed in user.
I have header component in which I have a nav called Admin which needs to be visible if admin logs in.
I have other component call signin component in which when admin sign in I need to pass that value to header component such that Admin nav shows up.
My requirement is similar to React: how to pass props from child to parent to another child?
but my signin component is in router.
On successful sign in I am routing user to homepage and setting value in local storage but my header component is not re-rendering.
Is there any way I can achieve this?
Kindly help.
App component
import React, { Component } from 'react';
import '../node_modules/video-react/styles/scss/video-react.scss';
import '../node_modules/bootstrap-vertical-tabs/bootstrap.vertical-tabs.min.css';
import routes from './routes';
import {withRouter} from 'react-router-dom';
import HeaderComponent from './components/header-component/header';
import './App.css';
import Footer from './components/footer/Footer';
import loader from './assets/loader.png';
import { Animated } from 'react-animated-css';
import firebase from "firebase";
class App extends Component {
constructor(props){
super(props);
this.props = props;
this.state = {
authUser:null
}
this.handleSignInHeader = this.handleSignInHeader.bind(this);
}
onSignIn(data){
console.log(data);
}
componentDidMount(){
firebase.auth().onAuthStateChanged(authUser =>{
authUser ? this.setState(() => ({ authUser })) : this.setState(() => ({ authUser: null }));
})
console.log(this.state)
}
handleSignInHeader(){
console.log('Sign handleSignInHeader method triggered')
}
render() {
return (
<div className="App" >
<div className="logo-wrapper ">
<div className="image-wrapper">
<Animated animationIn="bounce infinite" >
<img alt="loader" src={loader}/>
</Animated>
</div>
</div>
<div className="container-fluid">
<div className="row set-min-height"><HeaderComponent/></div>
<div className="row route-container" >
{routes}
</div>
<div className="row">
<Footer/>
</div>
</div>
</div>
);
}
}
export default App;
Sign in component
import React, { Component } from 'react';
import './sign-in.css';
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import { auth } from '../../firebase/index';
import { Link } from 'react-router-dom';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import TextField from '#material-ui/core/TextField';
import { withSnackbar } from 'notistack';
import firebase from "firebase";
const INITIAL_STATE = {
email: '',
password: '',
error: null,
openDialog: false,
resetEmail:''
};
const byPropKey = (propertyName, value) => () => ({
[propertyName]: value,
});
class Signin extends Component{
constructor(props) {
super(props);
this.resetPassword = this.resetPassword.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleReset = this.handleReset.bind(this);
this.state = { ...INITIAL_STATE };
}
resetPassword(){
console.log('reset password clicked');
this.setState({
openDialog: true
})
}
handleCancel(){
this.setState({
openDialog: false
})
}
handleReset(){
const { enqueueSnackbar } = this.props;
console.log(this.state)
let auth = firebase.auth();
this.setState({
openDialog: false
})
auth.sendPasswordResetEmail(this.state.resetEmail).then(function() {
// Email sent.
enqueueSnackbar('Email sent successfully');
}).catch(function(error) {
// An error happened.
let err= error.message
enqueueSnackbar(err);
});
}
onSubmit = (event) => {
const { enqueueSnackbar } = this.props;
console.log('value of props on submit logged',this.props)
const {
email,
password,
} = this.state;
auth.doSignInWithEmailAndPassword(email, password)
.then(() => {
this.setState({ ...INITIAL_STATE });
enqueueSnackbar('sign in succesfull');
console.log(firebase.auth().currentUser);
let authUser = firebase.auth().currentUser;
console.log(authUser);
localStorage.setItem('authUser',JSON.stringify(authUser));
localStorage.setItem('isUserLoggedIn',true);
this.props.onSignIn('sign in Successfull');
this.props.history.push('/');//routing to landing page
})
.catch(error => {
this.setState(byPropKey('error', error));
console.log(error)
});
event.preventDefault();
}
render(){
const {
email,
password
} = this.state;
return(
<div className="login-body">
<div className="hybrid-login-form">
<div className="sign-in-content">
<h1>Sign In</h1>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label className="set-label-pos" for="Email">Email</Label>
<input value={email} className="form-control" onChange={event => this.setState(byPropKey('email', event.target.value))}
type="text" placeholder="Email" />
</FormGroup>
<FormGroup>
<Label className="set-label-pos" for="Password">Password</Label>
<input className="form-control" value={password} onChange={event => this.setState(byPropKey('password', event.target.value))}
type="password" placeholder="Password" />
</FormGroup>
<Button className="btn btn-danger sign-in-btn" size="lg" type="submit">Sign In</Button>
<FormGroup check className="remember-me">
<Label className="set-label-pos" check>
<Input type="checkbox" />{' '} Remember me</Label>
<Label className="set-frgt-pass" onClick={this.resetPassword}>Forgot Password</Label>
</FormGroup>
</Form>
</div>
<div className="signup-content">
New to Faraday? <Link to="/signup">Sign up now.</Link>
</div>
</div>
<Dialog open={this.state.openDialog} onClose={this.handleClose} aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description">
<DialogTitle id="alert-dialog-title">{"Reset Password"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Please enter your registered email address, an email will be sent for resetting password.
</DialogContentText>
</DialogContent>
<TextField
autoFocus
margin="dense"
id="name"
label="Email Address"
type="email"
onChange={event => this.setState(byPropKey('resetEmail', event.target.value))}
/>
<DialogActions>
<Button onClick={this.handleCancel} color="primary">
Cancel
</Button>
<Button onClick={this.handleReset} color="primary" autoFocus>
Reset
</Button>
</DialogActions>
</Dialog>
</div>
)
}
}
export default withSnackbar(Signin);
Header component
import React, { Component } from 'react';
import {
Collapse,
Navbar,
NavbarToggler,
Nav,
NavItem,
NavLink
} from 'reactstrap';
import './header.css';
import HeaderCollapse from './header-collapse/header-collapse';
import logo from '../../assets/logo.png';
import usericon from '../../assets/user.png';
import { ListGroup, ListGroupItem } from 'reactstrap';
import { Link } from 'react-router-dom';
class HeaderComponent extends Component {
headerList = [
{'Id':1,'Title':'K-12 Physics','submenu':['Video Lectures & Practice','White Papers','Revision Tree & Learning curve']},
{'Id':2,'Title':'Scinema','submenu':['Story of science','Modern Science','Learn Science']},
{'Id':3,'Title':'WorkShops','submenu':['Argon','Neon','Xenon']},
// {'Id':4,'Title':'Ed-Tech','submenu':['Item1','Item2','Item3']} // future sprint
];
constructor(props) {
super(props);
this.state = {
isOpen: false,
activeItem: -1,
showCollapseBar: false,
showUserAction: false,
isAuthUser:false,
selData:[]
};
this.toggle = this.toggle.bind(this);
this.hideCollapse = this.hideCollapse.bind(this);
this.showActionModel = this.showActionModel.bind(this);
this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
this.logout = this.logout.bind(this);
this.updateState = this.updateState.bind(this);
this.onclickOutsideHeaderContainer = this.onclickOutsideHeaderContainer.bind(this);
this.handleItemClick = this.handleItemClick.bind(this);
this.collapseCallback = this.collapseCallback.bind(this);
this.setheaderContainerRef = this.setheaderContainerRef.bind(this);
console.log('header props',this.props)
}
componentDidMount() {
console.log('header component testing', localStorage.getItem('isUserLoggedIn'))
document.addEventListener('mousedown', this.handleClickOutside);
console.log('Logged in user details',localStorage.getItem('authUser'))
this.updateState();
}
updateState(){
console.log('update state triggered from header compoenet')
this.setState({isAuthUser: localStorage.getItem('isUserLoggedIn')});
console.log(localStorage.getItem('authUser'))
}
// showAdminNav(){
// console.log('show admin nav triggered')
// }
onSignIn(){
console.log('On Sign in Method call')
}
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
this.setState({
showUserAction: !this.state.showUserAction
});
}
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
// some code..
//alert('mobile biew')
if(event.path[0].className !== 'actionLink.nav-link'){
return;
}
//this.hideCollapse();
}
}
onclickOutsideHeaderContainer(event){
if(!this.headerContainerRef.contains(event.target))
this.hideCollapse()
}
handleItemClick(index,data) {
console.log(data)
this.setState({
activeItem: index,
showCollapseBar: true,
selData:data
})
}
toggle() {
this.setState({
isOpen: !this.state.isOpen,
//showCollapseBar: !this.state.showCollapseBar /**Commented to fix toggle */
});
this.hideCollapse();
}
hideCollapse(){
this.setState({
showCollapseBar: false
});
}
collapseCallback = (data) => {
if (data === 'hide Collapse') {
this.setState({
activeItem: -1,
showCollapseBar: false
})
}
}
showActionModel(){
this.setState({
showUserAction: !this.state.showUserAction
});
}
setWrapperRef(node) {
this.wrapperRef = node;
}
setheaderContainerRef(node){
this.headerContainerElement = node;
}
logout(){
console.log('logout method triggered')
localStorage.setItem('authUser',null);
localStorage.setItem('isUserLoggedIn',false);
this.props.history.push('/');
}
render() {
const showCollapseBar = this.state.showCollapseBar;
const showActionModel = this.state.showUserAction;
const isUserLoggedIn = this.state.isAuthUser === "true" ? true : false;
let collapseBar = "null";
if (showCollapseBar) {
collapseBar = <HeaderCollapse data = {this.state.selData} callbackFromheader={this.collapseCallback}/>;
} else {
collapseBar = null;
}
const headerList = this.headerList.map((header, index) =>
<NavItem key={header.Id.toString()} className={this.state.activeItem === index ? 'active' : ''}>
<NavLink onClick={this.handleItemClick.bind(this, index,header)}>
{header.Title}
</NavLink>
</NavItem>
);
let actionList = null;
if(isUserLoggedIn){
actionList = <ListGroup>
<ListGroupItem>Profile</ListGroupItem>
<ListGroupItem onClick={this.logout}>Logout</ListGroupItem>
</ListGroup>;
}else{
actionList = <ListGroup>
<ListGroupItem><Link className="actionLink nav-link" to="/signin">Sign In</Link></ListGroupItem>
<ListGroupItem><Link className="actionLink nav-link" to="/SignUp">Not a member yet.? Sign Up Now</Link></ListGroupItem>
</ListGroup>;
}
//<img src={logo} height="60"/>
return (
<div className="header-container" id="header-container" >
<Navbar color="light" light expand="md" dark >
<Link to="/"><img src={logo} height="60"/></Link>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
{headerList}
<NavItem>
<Link to="/contacts" onClick={this.hideCollapse} className="actionLink nav-link">Contact</Link>
</NavItem>
<NavItem>
<Link className="actionLink nav-link" to="/managedata">Admin</Link>
</NavItem>
<NavItem>
{/* <Link className="actionLink nav-link" to=""> */}
<img id="user-icon" src={usericon} onClick={this.showActionModel}/>
{/* </Link> */}
</NavItem>
</Nav>
</Collapse>
</Navbar>
{showActionModel && <div id="user-actions" ref={this.setWrapperRef}>
{actionList}
</div>}
{collapseBar}
</div>
);
}
}
export default HeaderComponent;

componentDidMount gets called only once when the component is rendered. So make sure , you call your function updateState whenever you sign in or sign out.

I think calling updateState method inside onSignIn should solve the issue if I understand the code correctly.
onSignIn() {
this.updateState()
}

Related

Uncaught TypeError: Object (…) is not a function

I am using Paystack component in my react app,
and the the component requires passing a kind of object containing some required
values below is the mother component for the one holding the paystackButton componenet.
import React from 'react';
import DateRangePicker from 'react-bootstrap-daterangepicker';
import { getRangeOfDates } from 'helpers';
import { BookingModal } from './BookingModal';
import * as moment from 'moment';
import * as actions from 'actions';
import { ToastContainer, toast } from 'react-toastify';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import PScomponent from '../payments/paystack'
class Booking extends React.Component {
constructor() {
super();
this.bookedOutDates = [];
this.dateRef = React.createRef();
this.state = {
errors:[],
proposedBooking: {
startAt: '',
endAt: '',
guests: '',
rooms: '',
totalPrice: '',
days:1
},
modal: {
open: false
}
}
}
............
render() {
const { rental, auth: {isAuth} } = this.props;
const { startAt, endAt, guests, rooms, totalPrice, days } =
this.state.proposedBooking;
const price = (parseInt(totalPrice)+5000) * parseInt(rooms)
const publicKey = "pk_test_........."
const amount = price * 100;
console.log(days)
const componentProps = {
email:this.props.auth.email,
amount,
metadata: {
userName : this.props.auth.username,
phone:this.props.auth.contact,
},
publicKey,
text: "Pay Now",
onSuccess: (e) =>
console.log(e),
onClose: () => alert("Wait! Don't leave :("),
}
//console.log(this.props.auth)
return (
<div className='booking' style={{marginBottom: '10px', padding: '0', border:'none'}}>
<ToastContainer />
<h3 className='booking-price'>NG{rental.dailyRate} <span className='booking-per-night'>per night</span></h3>
<hr></hr>
{ !isAuth &&
<Link className='btn btn-bwm btn-confirm btn-block' to={{pathname: '/login'}}>Login to book place!</Link>
}
{ isAuth &&
<React.Fragment>
<div className='form-group'>
<label htmlFor='dates'>Dates</label>
<DateRangePicker onApply={this.handleApply} isInvalidDate={this.checkInvalidDates} opens='left' containerStyles={{ display: 'block' }}>
<input ref={this.dateRef} id='dates' type='text' className='form-control'></input>
</DateRangePicker>
</div>
<div className='form-group'>
<label htmlFor='guests'>Guests</label>
<input value={guests} onChange={(event) => { this.selectGuests(event) }} type='number' className='form-control' id='guests' aria-describedby='emailHelp' placeholder=''></input>
</div>
<div className='form-group'>
<label htmlFor='guests'>Rooms</label>
<input value={rooms} onChange={(event) => { this.selectRoomNum(event) }} type='number' className='form-control' id='Rooms' aria-describedby='emailHelp' placeholder=''></input>
</div>
<button disabled={!startAt || !endAt || !guests} onClick={() => { this.confirmProposedData() }} className='contact_btn'>PAY FOR RESERVATION</button>
</React.Fragment>
}
{
this.state.modal.open && <PScomponent componentProps={componentProps}/>
}
</div>
)
}
}
function mapStateToProps(state){
return {
auth: state.auth
}
}
export default connect(mapStateToProps)(Booking)
inside PScomponent component .
import React from "react"
import {PaystackButton} from "react-paystack"
import "./P_Scomponent.css"
export default function PScomponent (props){
const { componentProps } = props;
//console.log(componentProps)
return (
<div className="P_Scomponent">
<PaystackButton className="paystack-button" {...componentProps} />
</div>
)
}
//
but yet the browser still give me the following error
i dont know where the error is coming from.
index.es.js:6 Uncaught TypeError: Object(...) is not a function
I finally got it working all I had to do was to downdate to a lower version of the react-paystack the version that worked for me is 2.0.2.

Unhandled Rejection (Error) in ReactJS, implementing files causes error

I'm trying to implement some search features for an online book store with reactjs. I found a good repo that uses the google book api and decided to implement it on my project to see how it would work. But I'm getting the following error:
enter image description here
my github is: https://github.com/luismir15/CEN4010.git branch: luis
//code implemented by jason rivera
import React, { Component } from 'react';
import BookList from './BookList';
import SearchBox from './SearchBox';
import request from 'superagent';
class Books extends Component {
constructor(props){
super(props)
this.state = {
books: [],
searchField: '',
sort: ''
}
}
componentDidMount() {
request
.get("https://www.googleapis.com/books/v1/volumes")
.query({ q: this.state.searchField })
.then((data) => {
this.setState({ books: [...data.body.items] })
})
}
handleSubmit = (e) => {
e.preventDefault();
request
.get("https://www.googleapis.com/books/v1/volumes")
.query({ q: this.state.searchField })
.then((data) => {
console.log(data);
this.setState({ books: [...data.body.items] })
})
}
handleChange = (e) => {
this.setState({ searchField: e.target.value })
}
handleSort = (e) => {
this.setState({ sort: e.target.value});
}
render() {
const filteredBooks = this.state.books.sort((a, b) => {
const price1 = a.saleInfo.hasOwnProperty('listPrice') == false ? "$0.00" : a.saleInfo.listPrice.amount;
const price2 = b.saleInfo.hasOwnProperty('listPrice') == false ? "$0.00" : b.saleInfo.listPrice.amount;
if(this.state.sort == 'Newest'){
console.log("in newest")
return parseInt(b.volumeInfo.publishedDate.substring(0, 4)) - parseInt(a.volumeInfo.publishedDate.substring(0, 4));
}
else if(this.state.sort == 'Oldest'){
return parseInt(a.volumeInfo.publishedDate.substring(0, 4)) - parseInt(b.volumeInfo.publishedDate.substring(0, 4));
}
else if(this.state.sort == 'High'){
return parseInt(b.volumeInfo.averageRating) - parseInt(a.volumeInfo.averageRating);
}
else if(this.state.sort == 'Low'){
return parseInt(a.volumeInfo.averageRating) - parseInt(b.volumeInfo.averageRating);
}
else if(this.state.sort === 'Expensive'){
return parseInt(price2) - parseInt(price1);
}
else if(this.state.sort === 'Cheap'){
return parseInt(price1) - parseInt(price2);
}
return;
})
return (
<div className="wrapper">
<SearchBox
data={this.state}
handleSubmit={this.handleSubmit}
handleChange={this.handleChange}
handleSort={this.handleSort}
/>
<BookList books={filteredBooks}/>
</div>
);
}
}
export default Books;
import React, { Component } from 'react';
import BookCard from './BookCard';
const BookList = (props) => {
return (
<div className="list">
{
props.books.map((book) => {
return <BookCard key={book.id} info={book} />
})
}
</div>
);
}
export default BookList;
import React, { Component } from 'react';
const SearchBox = (props) => {
return (
<div className="search-area">
<form onSubmit={props.handleSubmit}>
<input onChange={props.handleChange} placeholder="Search books" type="text"/>
<button type="submit">Search</button>
<select value={props.sort} onChange={props.handleSort}>
<option value="" disabled selected>Sort</option>
<option value="Newest">Newest</option>
<option value="Oldest">Oldest</option>
<option value="High">High to Low</option>
<option value="Low">Low to High</option>
<option value="Expensive">$$$-$</option>
<option value="Cheap">$-$$$</option>
</select>
</form>
</div>
);
}
export default SearchBox;
import React, { Component } from 'react';
const BookCard = (props) => {
const { volumeInfo } = props.info;
const { saleInfo } = props.info;
const {title, authors, averageRating, subtitle, publishedDate} = props.info.volumeInfo;
const price = saleInfo.hasOwnProperty('listPrice') == false ? "$0.00" : saleInfo.listPrice.amount;
const thumbNail = volumeInfo.hasOwnProperty('imageLinks') == false ? "https://vignette.wikia.nocookie.net/pandorahearts/images/a/ad/Not_available.jpg/revision/latest?cb=20141028171337" : volumeInfo.imageLinks.thumbnail;
const publishYear = volumeInfo.hasOwnProperty('publishedDate') == false ? volumeInfo['publishedDate'] = "0000" : volumeInfo.publishedDate;
return (
<div className="card-container">
<img src={thumbNail} alt=""/>
<div className="desc">
<h2>{title}</h2>
<p>Author: {authors}</p>
<p>Price: {price}</p>
<p>Raiting: {averageRating == "0.00" ? "Not available" : averageRating}</p>
<p>Published: {publishYear == "0000" ? "Not available" : publishYear.substring(0,4)}</p>
</div>
</div>
);
}
export default BookCard;
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import '../style/browsing.css';
import Books from '../component/Books';
const Home = () => {
return (
<div>
<ul className="flexbox-container">
<div className="browsing">
<Books/>
</div>
</ul>
</div>
);
}
export default Home;
import React from 'react';
import './index.css';
import './style/browsing.css';
import Home from './pages/Home';
import Register from './pages/Register';
import Login from './pages/Login';
import Orders from './pages/Orders';
import BookDetails from './pages/BookDetails';
import ShopCart from './pages/ShopCart';
import Profile from './pages/Profile';
//import Books from './component/Books';
import { Route, HashRouter, NavLink } from 'react-router-dom';
// NPM RUN CLIENT is the updated src folder, (NPM RUN SERVER/NPM START) runs build in my case which is the old green template
//Use ctrL + C to stop the server
//Always run NPM INSTALL on a newly cloned file
//Do not push updates to master branch, push to your own branch PLZ
//updated file structure on my branch (miguel) 2/17/20
//npm install after downloading/ npm install --save react-bootstrap mighe be needed for BookDetails to work
//npm npm run client to run this package
const App = () => (
<div>
<HashRouter>
<div>
<NavLink to="/" style={{ textDecoration: 'none' }}>
<h1><i class="material-icons">menu_book</i> GeekText</h1>
</NavLink>
<ul className="header">
<li><NavLink exact to="/">Home</NavLink></li>
<li><NavLink to="/Login">Login</NavLink></li>
<li><NavLink to="/Orders">Orders</NavLink></li>
<li><NavLink to="/BookDetails">Book Details</NavLink></li>
<li><NavLink to="/Profile">Profile</NavLink></li>
<li>
<NavLink to="/ShopCart">
<i class="material-icons md-dark md-24">shopping_cart</i>
</NavLink>
</li>
</ul>
<div className="content">
<Route exact path="/" component={Home} />
<Route path="/Register" component={Register} />
<Route path="/Login" component={Login} />
<Route path="/Orders" component={Orders} />
<Route path="/BookDetails" component={BookDetails} />
<Route path="/ShopCart" component={ShopCart} />
<Route path="/Profile" component={Profile} />
</div>
</div>
</HashRouter>
</div>
);
export default App;

My filter search list in react doesn't display the filtered list and runs into the error

This is Owner component(Owner.js) where I am implementing a search filter which should display restaurant with the same name as in search. But when I try to use the restaurant and implement filter search It goes to error. I should get the list of restaurant from my pre-existing restaurant list in owner dashboard.
import React, { Component } from "react";
import Restaurant from "../customer/Restaurant";
export default class Owner extends Component {
constructor() {
super();
this.state = {
search: ""
};
}
updateSearch(event) {
this.setState({
search: event.target.value.substr(0, 25)
});
}
render() {
let filteredRestaurants = this.props.restaurants;
return (
<div>
<h1> Welcome Owner </h1> <br />
<ul>
{" "}
{filteredRestaurants.map(res => {
return <restaurants res={<Restaurant />} key={res.name} />;
})}
</ul>{" "}
<input
type="text"
Value={this.state.search}
onChange={this.updateSearch.bind(this)}
/>{" "}
<Restaurant />
</div>
);
}
}
This is Restaurant.js which display the restaurant details in Owner.js.
import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { getRestaurant } from "../../actions/getRestaurants";
export class Restaurant extends Component {
static propTypes = {
// restaurants: PropTypes.array.isRequired,
getRestaurantName: PropTypes.func
};
componentDidMount() {
this.props.getRestaurant();
}
render() {
const contentKeys = Object.keys(this.props.restaurants);
// console.log(JSON.parse(this.props.restaurants))
return (
<div className="row">
{contentKeys.map(t =>
[this.props.restaurants[t]].map(res => (
<div className="col-md">
<div className="card" style={cardWidth}>
<img className="card-img-top" src="..." alt="Card image cap" />
<div className="card-body">
<h5 className="card-title">{res.Name}</h5>
<p className="card-text">
<h6>{res.Address}</h6>
<h6>{res.City}</h6>
<h6>{res.zipcode}</h6>
<h6>Open:{res.Hours.Open}</h6>
<h6>Close:{res.Hours.Close}</h6>
</p>
<a href="#" className="btn btn-primary">
Go somewhere
</a>
</div>
</div>
</div>
))
)}
</div>
);
}
}
const cardWidth = {
width: "18rem"
};
const mapStateToProps = state => ({
restaurants: state.restaurantReducer.restaurants
});
export default connect(
mapStateToProps,
{ getRestaurant }
)(Restaurant);
//export default Restaurant;
I am having an error in filtering restaurant from owner dashboard. As return statement does not return any value and runs into error.
{filteredRestaurants.map(res => {
return <restaurants res={<Restaurant />} key={res.name} />;
})}
You're storing search query in a state, but don't use it when rendering filteredRestaurants.
You should filter them before mapping. Something like that:
const filteredRestaurants = this.props.restaurants.filter(res => res.name.includes(this.state.search);
// ...
filteredRestaurants.map(res => <Restaurant key={res.name} />)
Also, you can make it much easier with React Hooks API, if you're using 16.8+ React.

React.js Form - How To Include All Values On Final Page?

So I have built a Wizard Form using React-Final-Form that I am using in my sign-up page. I am trying to figure out how I can display all user inputs on the final page as a way for the user to double-check/verify their inputs before submitting. Any help would be greatly appreciated!
(P.S. - I tried researching this before posting, but all I was able to find was storing user inputs in Redux and accessing them from there, which I'd like to avoid, if at all possible.)
Here is an example link that shows what I want to do - Please feel free to fork and play around with it if you are trying to figure out a solution! https://codesandbox.io/s/0332k02x0v
Here is the code, shortened to include only the relevant bits:
My Wizard.js page:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Form } from "react-final-form";
class Wizard extends Component {
static propTypes = {
onSubmit: PropTypes.func.isRequired
};
static Page = ({ children }) => children;
constructor(props) {
super(props);
this.state = {
page: 0,
values: props.initialValues || {}
};
}
next = values =>
this.setState(state => ({
page: Math.min(state.page + 1, this.props.children.length - 1),
values
}));
previous = () =>
this.setState(state => ({
page: Math.max(state.page - 1, 0)
}));
validate = values => {
const activePage = React.Children.toArray(this.props.children)[
this.state.page
];
return activePage.props.validate ? activePage.props.validate(values) : {};
};
handleSubmit = values => {
const { children, onSubmit } = this.props;
const { page } = this.state;
const isLastPage = page === React.Children.count(children) - 1;
if (isLastPage) {
return onSubmit(values);
} else {
this.next(values);
}
};
render() {
const { children } = this.props;
const { page, values } = this.state;
const activePage = React.Children.toArray(children)[page];
const isLastPage = page === React.Children.count(children) - 1;
return (
<Form
initialValues={values}
validate={this.validate}
onSubmit={this.handleSubmit}
>
{({ handleSubmit, submitting, values }) => (
<form onSubmit={handleSubmit}>
{activePage}
<div className="buttons">
{page > 0 && (
<button type="button" onClick={this.previous}>
« Previous
</button>
)}
{!isLastPage && <button type="submit">Next »</button>}
{isLastPage && (
<button type="submit" disabled={submitting}>
Submit
</button>
)}
</div>
{/* <pre>{JSON.stringify(values, 0, 2)}</pre> */}
</form>
)}
</Form>
);
}
}
export default Wizard;
My index.js page:
import React, { Component } from "react";
import { Field } from "react-final-form";
import formatString from "format-string-by-pattern";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Wizard from "./Wizard";
import Styles from "./Styles";
import { addUser } from "../../../actions/authActions";
class ReactFinalForm2 extends Component {
state = {};
render() {
const onSubmit = async values => {
this.props.addUser(values);
// API query here
};
const Error = ({ name }) => (
// Error handing here
);
return (
<Styles>
<div>
<Wizard initialValues={{}} onSubmit={onSubmit}>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page>
{/* *** THIS IS WHERE I WOULD LIKE TO DISPLAY ALL PREVIOUS VALUES (SO THE USER CAN CONFIRM / DOUBLE-CHECK THEIR INPUTS BEFORE SUBMITTING) *** */}
</Wizard.Page>
</Wizard>
</div>
</Styles>
);
}
}
ReactFinalForm2.propTypes = {
addUser: PropTypes.func.isRequired
};
export default connect(
null,
{ addUser }
)(ReactFinalForm2);
I have added a state to the parent component. Changing this state on every submit from the child. I have JSON stringify the state in parent component. As you said no need to use redux, this is the workaround I came with. Still your code has a potential for improvements. Please check this working sandbox:
[ https://codesandbox.io/s/zrvloq4o6x ]
Wizard.js change
handleSubmit = values => {
const { children, onSubmit } = this.props;
const { page } = this.state;
const isLastPage = page === React.Children.count(children) - 1;
if (isLastPage) {
return onSubmit(values);
} else {
this.next(values);
}
// Change added
this.props.onStateChange(values);
};
Index.js
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Field } from "react-final-form";
import Wizard from "./Wizard";
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const onSubmit = async values => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const Error = ({ name }) => (
<Field
name={name}
subscribe={{ touched: true, error: true }}
render={({ meta: { touched, error } }) =>
touched && error ? <span>{error}</span> : null
}
/>
);
const required = value => (value ? undefined : "Required");
let data = {};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onStateChange = this.onStateChange.bind(this);
}
onStateChange = values => {
this.setState({ data: values });
console.log(values);
};
render() {
return (
<Styles>
<h1>🏁 React Final Form Example</h1>
<h2>Wizard Form</h2>
<a href="https://github.com/erikras/react-final-form#-react-final-form">
Read Docs
</a>
<p>
Notice the mixture of field-level and record-level (or{" "}
<em>page-level</em> in this case) validation.
</p>
<Wizard
initialValues={{}}
onStateChange={this.onStateChange}
onSubmit={onSubmit}
>
<Wizard.Page>
<div>
<label>First Name</label>
<Field
name="firstName"
component="input"
type="text"
placeholder="First Name"
validate={required}
/>
<Error name="firstName" />
</div>
<div>
<label>Last Name</label>
<Field
name="lastName"
component="input"
type="text"
placeholder="Last Name"
validate={required}
/>
<Error name="lastName" />
</div>
</Wizard.Page>
<Wizard.Page
validate={values => {
const errors = {};
if (!values.notes) {
errors.notes = "Required";
}
return errors;
}}
>
<div>
<label>Best Stooge?</label>
<div>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="larry"
/>{" "}
Larry
</label>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="moe"
/>{" "}
Moe
</label>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="curly"
/>{" "}
Curly
</label>
</div>
</div>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
<Error name="notes" />
</div>
</Wizard.Page>
<Wizard.Page>
<div>
<p>
<b>Display all previous values here for user verification </b>
<br />
<i>{JSON.stringify(this.state.data, 0, 2)}</i>
</p>
</div>
</Wizard.Page>
</Wizard>
</Styles>
);
}
}
render(<App />, document.getElementById("root"));

React Js Reversed array un reverses on clicks

So I have an array that gets pulled from a database and I have reversed it so that the newest db entry goes to the top when you click a button on the page which opens a little modal style window the displayed array flips and goes from oldest to newest for some reason and I don't know why.
here is the code:
import React, { Component } from 'react';
import axios from 'axios';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import { Modal, ModalHeader, ModalTitle, ModalClose, ModalFooter, ModalBody } from 'react-modal-bootstrap';
import TextField from 'material-ui/TextField';
class ViewNoteDetails extends Component {
constructor(props) {
super(props);
this.NewNote = this.NewNote.bind(this);
this.handleChange = this.handleChange.bind(this);
}
state = {
Case: this.props.Case,
notesToShow: this.props.Case.slice(0, parseInt(this.props.AmountToShow, 10)),
isOpen: false,
note: '',
}
NewNote() {
const self = this;
if (this.state.note !== '') {
axios.post('http://******'
+ window.location.href.split('view/')[1]
+ '/' + self.state.note
).then(function (res) {
if (res.data === "Updated") {
self.hideModal();
window.location.reload();
}
})
.catch(function (error) {
console.log(error);
});
} else {
window.alert("Cannot Enter A Blank Note")
}
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
openModal = () => {
this.setState({
isOpen: true
});
};
hideModal = () => {
this.setState({
isOpen: false
});
};
render() {
const pullRight = {
float: "right",
display: "inline",
}
const inline = {
display: "inline",
}
const Overflow = {
overflow: "auto",
width: "100%",
height: "50vw",
}
return (
<MuiThemeProvider>
<div>
<Modal isOpen={this.state.isOpen} onRequestHide={this.hideModal}>
<ModalHeader>
<ModalClose onClick={this.hideModal} />
<ModalTitle>Enter Your Note</ModalTitle>
</ModalHeader>
<ModalBody>
<TextField hintText="Enter Note" name="note" fullWidth={true} onChange={this.handleChange} />
</ModalBody>
<ModalFooter>
<RaisedButton label="Save Note" secondary={true} onClick={() => this.NewNote()} />
<RaisedButton label="Cancel Note" secondary={true} onClick={() => this.hideModal()} />
</ModalFooter>
</Modal>
<br />
<h1 id="TOP" style={inline}>Note Details</h1>
<RaisedButton label="New Note" style={pullRight} secondary={true} onClick={() => this.openModal()} />
<br />
<br />
<div style={Overflow}>
{this.state.notesToShow.reverse().map(function (note, index) {
return (
<div key={note.NotePK}>
<p className="well well-lg">
{note.CreationDate.split('T')[0]} # {note.CreationDate.split('T')[1].split('.')[0]} : {note.Note}
</p>
</div>
);
})}
</div>
<br />
</div>
</MuiThemeProvider>
);
}
}
***** is in replacement of the database location
when you click the new note button the order reverses on the rendered notes
so if it was:
note 1
note 2
note 3
on click of new note it would change to
note 3
note 2
note 1
why does it do this and how do i fix this.
Don't reverse it in your render method. Every time it gets re-rendered you will reverse it. So what happens is probably is that it is getting reversed a second time when you open the modal window.
Do it here for once
state = {
Case: this.props.Case,
notesToShow: this.props.Case.slice(0, parseInt(this.props.AmountToShow, 10)).reverse(),
isOpen: false,
note: '',
}

Categories

Resources