I have a React project and the Portals were implemented. Profile.js is the children component of Modal.js. My question is when I run npm start locally, Portals works fine (Profile component can be toggled and it pops up). However, after I deploy the code to gh-pages, the portal doesn't show up (when I click profile, nothing pops up). But when looking at the console, it shows the modal div is inserted. I am wondering how I can fix it? I tried on multiple browsers with the same issue. Thank you
App.js
import './App.css';
import React, { useState, useEffect, Suspense } from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
import 'tachyons';
import Navigation from './components/Navigation/Navigation';
import Slide from './components/Slide/Slide';
import Modal from './components/Modal/Modal';
import Profile from './components/Profile/Profile';
const Ingredient = React.lazy(() => import('./components/Ingredient/Ingredient'));
const RecommendRecipe = React.lazy(() => import('./components/RecommendRecipe/RecommendRecipe')) ;
const Register = React.lazy(() => import('./components/Register/Register'));
const Signin = React.lazy( ()=> import('./components/Signin/Signin')) ;
const SavedRecipes = React.lazy(() => import('./components/SavedRecipes/SavedRecipes')) ;
const initialState = {
isLogin: false,
user: {
email: '',
username: '',
create_on: '',
user_id: '',
dob: '',
recipes_number: ''
}
}
function App() {
const [ user, setUser ] = useState(initialState);
const [ isProfileOpen, setIsProfileOpen] = useState(false);
useEffect(() => {
const token = window.localStorage.getItem('token')
if (token) {
return fetch('https://warm-reef-43761.herokuapp.com/signin', {
method: 'post',
headers: {
'content-type': 'Application/json',
'authorization': token
}
})
.then(resp => resp.json())
.then(data => {
if (data.id) {
return fetch(`https://warm-reef-43761.herokuapp.com/profile/${data.id}`, {
method: 'get',
headers: {
'Content-Type': 'application/json',
'authorization': token
}
})
.then(resp => resp.json())
.then(user => {
loadUser(user)
})
.catch(err => console.log('unable to refresh'))
}
})
.catch(console.log)
}
}, [])
const loadUser = (data) => {
setUser({
isLogin: true,
user: {
email: data.email,
username: data.username,
create_on: data.create_on,
user_id: data.user_id,
dob: data.dob,
recipes_number: data.recipes_number
}
});
}
const signout = (event) => {
setUser(initialState)
window.localStorage.removeItem('token')
}
const toggleModal = () => {
setIsProfileOpen(!isProfileOpen)
}
return (
<div className="App">
<Router basename={process.env.PUBLIC_URL}>
<Navigation
isLogin={user.isLogin} signout={signout} toggleModal={toggleModal}/>
{ isProfileOpen &&
<Modal>
<Profile toggleModal={toggleModal} user={user.user} loadUser={loadUser}/>
</Modal>
}
<Suspense fallback={<span>Loading</span>}>
<Switch>
<Route path='/' exact component = {Slide} />
<Route path='/register' >
<Register loadUser={loadUser} />
</Route>
<Route path='/signin'>
<Signin loadUser={loadUser} />
</Route>
<Route path='/foodlist' >
<Ingredient isLogin={user.isLogin}/>
</Route>
<Route path='/recommendrecipes' >
<RecommendRecipe user={user.user} loadUser={loadUser} isLogin={user.isLogin} />
</Route>
<Route path='/savedrecipes' >
<SavedRecipes user={user.user} loadUser={loadUser}/>
</Route>
</Switch>
</Suspense>
</Router>
</div>
);
}
export default App;
Modal.js
import { Component } from 'react';
import ReactDOM from 'react-dom';
import './Modal.css'
const modalRoot = document.getElementById('modal-root');
class Modal extends Component {
constructor(props) {
super(props)
this.el = document.createElement('div')
}
componentDidMount() {
modalRoot.appendChild(this.el)
}
componentWillUnmount() {
modalRoot.removeChild(this.el)
}
render() {
return ReactDOM.createPortal(this.props.children, this.el)
}
}
export default Modal;
Profile.js
import Button from 'react-bootstrap/Button';
import { useState } from 'react';
import './Profile.css'
function Profile({ toggleModal, user, loadUser }) {
const [ username, setUsername ] = useState(user.username);
const [ dob, setDob ] = useState(user.dob)
const onInputChange = (event) => {
switch (event.target.name) {
case 'username':
setUsername(event.target.value)
break
case 'date':
setDob(event.target.value)
break
default:
return
}
}
const onEditButton = () => {
setDob(null)
}
const onSaveSubmit = (data) => {
fetch(`https://warm-reef-43761.herokuapp.com/profile/${user.user_id}`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'authorization': window.localStorage.getItem('token')
},
body: JSON.stringify({ formUpdate: data
})
})
.then(resp => resp.json())
.then(data => {
loadUser({...user, ...data})
toggleModal()
})
.catch(err => console.log(err))
}
return (
<div className='modal'>
<div className="col-md-8">
<div className="card mb-3">
<div className="card-body">
<div className="row">
<div className="col-sm-11" >
</div>
<div className="col-sm-1 mb-3">
<Button onClick={toggleModal} variant="info" size='sm'>x</Button>
</div>
</div>
<div className="row">
<div className="col-sm-3 align-self-center">
<h6 className="mb-0">Username</h6>
</div>
<div className="col-sm-7">
<input onChange={onInputChange} name='username' placeholder={user.username}/>
</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3 align-self-center">
<h6 className="mb-0">Email</h6>
</div>
<div className="col-sm-9 ">
<h6> {user.email} </h6>
</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3 align-self-center">
<h6 className="mb-0">Date of Birth</h6>
</div>
{ dob === undefined || dob === null ?
<div className="col-sm-9 align-self-center">
<input type='date' name='date' onChange={onInputChange} />
</div>
:
<>
<div className="col-sm-7 align-self-center">
<h6>{new Date(dob).toLocaleDateString()}</h6>
</div>
<div className="col-sm-2">
<Button variant="info" onClick={onEditButton}>Edit</Button>
</div>
</>
}
</div>
<hr />
<div className="row">
<div className="col-sm-3" >
<h6 className="mb-0">Saved Recipes</h6>
</div>
<div className="col-sm-9 ">
{user.recipes_number}
</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Register on</h6>
</div>
<div className="col-sm-9 ">
{new Date(user.create_on).toLocaleDateString()}
</div>
</div>
<hr />
<div className="row">
<div className="col-sm-12">
<button className="btn btn-info ma2" onClick={() => onSaveSubmit({username, dob})}>Save</button>
<button className="btn btn-info ma2 " onClick={toggleModal}>Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default Profile;