I use client-side routes(HashRouter, Link). In App component i have 3 components - Home, Page1, Page2. And i want to get data from server and on Page1 display this data dynamicaly. But when i go to this page i have error:
When i don't configure Page1 as class and configure it such as const (just as in app.jsx Home component) all work fine, but when i try to configure it like a class, i get this error which i described below.
Here my code:
app.jsx
import React from 'react'
import {
HashRouter as Router,
Route,
Link
} from 'react-router-dom'
import {
Container,
Row,
Col
} from 'react-grid-system';
import Page1 from "./page1.jsx";
const Home = () => (
<div class="container-fixed">
<div class="row">
<div class="col-l-4">
<h2 class="underline">Home</h2>
</div>
</div>
</div>
)
const Subpage = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
const Page2 = ({ match }) => (
<div class="container-fixed">
<div class="row">
<div class="col-l-4">
<h2 class="underline">Subpages</h2>
<ul class="content-list">
<li class="content-list-item">
<Link to={`${match.url}/subpage1`}>
subpage1
</Link>
</li>
<li class="content-list-item">
<Link to={`${match.url}/subpage2`}>
subpage2
</Link>
</li>
<li class="content-list-item">
<Link to={`${match.url}/subpage3`}>
subpage3
</Link>
</li>
</ul>
<Route path={`${match.path}/:topicId`} component={Subpage}/>
<Route exact path={match.path} render={() => (
<h3>Please select a subpage.</h3>
)}/>
</div>
</div>
</div>
)
const App = () => (
<Router>
<Container>
<Row>
<Col md={2}>
<h2 class="underline">Menu</h2>
<ul class="content-list">
<li class="content-list-item">
<Link to="/">Home</Link>
</li>
<li class="content-list-item">
<Link to="/page1">Page1</Link>
</li>
<li class="content-list-item">
<Link to="/page2">Page2</Link>
</li>
</ul>
</Col>
<Col>
<Route exact path="/" component={Home}/>
<Route path="/page1" component={Page1}/>
<Route path="/page2" component={Page2}/>
</Col>
</Row>
</Container>
</Router>
)
export default App
page1.jsx
import React, {Component} from 'react';
const Row_ = function(props){
const {id, content} = props;
return (
<div>
id: {id}
content: {content}
</div>
);
}
class Page1 extends React.Component {
constructor(props){
super(props);
this.state = {
datas: [
{id: 14, content: "test"},
{id: 25, content: "test2"},
{id: 75, content: "test3"},
]
};
}
handleClick() {
let fetchedData = gerData();
this.addDataToHTML(fetchedData.id, fetchedData.content);
}
getData() {
fetch('/testdata', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(results => {
return results.json();
})
}
addDataToHTML(id, content){
const datas = [...this.state.datas,
{value: id, checked: content}
];
this.setState({
datas,
});
}
render(){
<div class="container-fixed">
<div class="row">
<div class="col-l-4">
<h2 class="underline">Page11</h2>
{this.state.datas.map((row, idx) => {
return(
<Row_
id={row.id}
content={row.content}
/>
)
})
}
<button onClick={this.handleClick}>
Get data
</button>
</div>
</div>
</div>
}
}
export default Page1
index.jsx
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import App from "./app.jsx";
import "../t_styles/css/components.min.css";
import "../t_styles/js/components.min.js";
import $ from "jquery";
ReactDOM.render((
<App></App>
), document.getElementById('index'))
1. use className instead of class.
2. add return statement in your render method of Page1 component
render(){
return (<div className="container-fixed">
<div className="row">
<div className="col-l-4">
<h2 className="underline">Page11</h2>
{this.state.datas.map((row, idx) => {
return(
<Row_
id={row.id}
content={row.content}
/>
)
})
}
<button onClick={this.handleClick}>
Get data
</button>
</div>
</div>
</div>)
}
Though I can't see the actual errors, my guess is that your handlers are not bound to the class instance, and therefore you can't access it via this.
So Either bind them to the class (this usually done inside the constructor):
this.handleClick = this.handleClick.bind(this);
this.getData= this.getData.bind(this);
this.addDataToHTML= this.addDataToHTML.bind(this);
Or use an arrow function syntax that will use this in a lexical context:
handleClick = () => {
let fetchedData = gerData();
this.addDataToHTML(fetchedData.id, fetchedData.content);
}
Related
I am new to react, I am strugging in troubleshooting the error or mistake I am making. When I click on submit button after filling the data the page neither refreshes nor it shows any success message. Can anyone plz help me with this
This is my app.js
import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import AuthService from "./services/auth.service";
import Login from "./components/login.component";
import Register from "./components/register.component";
import Home from "./components/home.component";
import Profile from "./components/profile.component";
import BoardUser from "./components/board-user.component";
import BoardAdmin from "./components/board-admin.component";
class App extends Component {
constructor(props) {
super(props);
this.logOut = this.logOut.bind(this);
this.state = {
showAdminBoard: false,
currentUser: undefined
};
}
componentDidMount() {
const user = AuthService.getCurrentUser();
if (user) {
this.setState({
currentUser: user,
showAdminBoard: user.roles.includes("ROLE_ADMIN")
});
}
}
logOut() {
AuthService.logout();
}
render() {
const { currentUser, showAdminBoard } = this.state;
return (
<Router>
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark">
<Link to={"/"} className="navbar-brand">
Flight Reservation System
</Link>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/home"} className="nav-link">
Home
</Link>
</li>
{showAdminBoard && (
<li className="nav-item">
<Link to={"/admin"} className="nav-link">
Admin
</Link>
</li>
)}
{currentUser && (
<li className="nav-item">
<Link to={"/user"} className="nav-link">
User
</Link>
</li>
)}
</div>
{currentUser ? (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/profile"} className="nav-link">
{currentUser.username}
</Link>
</li>
<li className="nav-item">
<a href="/login" className="nav-link" onClick={this.logOut}>
LogOut
</a>
</li>
</div>
) : (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/login"} className="nav-link">
Login
</Link>
</li>
<li className="nav-item">
<Link to={"/register"} className="nav-link">
Sign Up
</Link>
</li>
</div>
)}
</nav>
<div className="container mt-3">
<Switch>
<Route exact path={["/", "/home"]} component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
<Route exact path="/profile" component={Profile} />
<Route exact strict path="/user" component={BoardUser} />
<Route exact strict path="/admin" component={BoardAdmin} />
</Switch>
</div>
</div>
</Router>
);
}
}
export default App;
This is my board-admin.component.js:
import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import "../Navbar.css";
import AddComponent from "./add-component";
import DeleteComponent from "./delete-component";
import UpdateComponent from "./update-component";
import UserService from "../services/user.service";
export default class BoardAdmin extends Component {
constructor(props) {
super(props);
this.state = {
content: ""
};
}
componentDidMount() {
UserService.getAdminBoard().then(
response => {
this.setState({
content: response.data
});
},
error => {
this.setState({
content:
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
});
}
);
}
render() {
return (
<Router>
<div>
<div className="navbars">
<ul>
<li>
<Link className="link" to={"/add"} >
Add
</Link>
</li>
<li>
<Link className="link" to={"/update"} >
Update
</Link>
</li>
<li>
<Link className="link" to={"/delete"}>
Delete
</Link>
</li>
</ul>
</div>
<div >
<Switch>
<Route exact path="/add" component={AddComponent} />
<Route exact path="/update" component={UpdateComponent} />
<Route path="/delete" component={DeleteComponent} />
</Switch>
</div>
</div>
</Router>
);
}
}
This is my add-component.js:
import React, { Component } from "react";
import FlightsService from "../services/flights.service";
export default class AddComponent extends Component {
constructor(props) {
super(props);
this.onChangeName = this.onChangeName.bind(this);
this.onChangeFrom = this.onChangeFrom.bind(this);
this.onChangeTo = this.onChangeTo.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.onChangeFare = this.onChangeFare.bind(this);
this.saveFlight = this.saveFlight.bind(this);
this.newFlight = this.newFlight.bind(this);
this.state = {
id: null,
name: "",
from: "",
to: "",
date: "",
fare: "",
submitted: false
};
}
onChangeName(e) {
this.setState({
name: e.target.value
});
}
onChangeFrom(e) {
this.setState({
from: e.target.value
});
}
onChangeTo(e) {
this.setState({
to: e.target.value
});
}
onChangeDate(e) {
this.setState({
date: e.target.value
});
}
onChangeFare(e) {
this.setState({
fare: e.target.value
});
}
saveFlight() {
var data = {
name: this.state.name,
from: this.state.from,
to:this.state.to,
date:this.state.date,
fare:this.state.fare
};
FlightsService.create(data)
.then(response => {
this.setState({
id: response.data.id,
name: response.data.name,
from: response.data.from,
to: response.data.to,
date:response.data.date,
fare:response.data.fare,
submitted: true
});
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
newFlight() {
this.setState({
id: null,
name: "",
from: "",
to: "",
date: "",
fare:"",
submitted: false
});
}
render() {
return (
<div className="submit-form">
{this.state.submitted ? (
<div>
<h4>You submitted successfully!</h4>
<button className="btn btn-success" onClick={this.newFlight}>
Add
</button>
</div>
) : (
<div>
<div className="form-group">
<label htmlFor="title">Name</label>
<input
type="text"
className="form-control"
id="title"
required
value={this.state.name}
onChange={this.onChangeName}
name="title"
/>
</div>
<div className="form-group">
<label htmlFor="description">From</label>
<input
type="text"
className="form-control"
id="description"
required
value={this.state.from}
onChange={this.onChangeFrom}
name="description"
/>
</div>
<div className="form-group">
<label htmlFor="description">To</label>
<input
type="text"
className="form-control"
id="description"
required
value={this.state.to}
onChange={this.onChangeTo}
name="description"
/>
</div>
<div className="form-group">
<label htmlFor="description">Date</label>
<input
type="text"
className="form-control"
id="description"
required
value={this.state.date}
onChange={this.onChangeDate}
name="description"
/>
</div>
<div className="form-group">
<label htmlFor="description">Fare</label>
<input
type="text"
className="form-control"
id="description"
required
value={this.state.fare}
onChange={this.onChangeFare}
name="description"
/>
</div>
<button onClick={this.saveFlight} className="btn btn-success">
Submit
</button>
</div>
)}
</div>
);
}
}
This is my axios related data:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8002/api",
headers: {
"Content-type": "application/json"
}
});
This is my service:
import http from "../http-common";
class FlightsService {
create(data) {
return http.post("/flights", data);
}
update(id, data) {
return http.put(`/flights/${id}`, data);
}
delete(id) {
return http.delete(`/flights/${id}`);
}
}
export default new FlightsService();
have you tried annon functions ?
<button onClick={this.saveFlight} className="btn btn-success">
into
<button onClick={()=>{this.saveFlight()}} className="btn btn-success">
you are also binding the function of the click handler to the class of the component. I'm not sure if that is correct (not 100% on react best practices), I haven't dove too deeply into react - but using a master click Handler that handles all click events at the app level has been my strategy when binding functions... that has worked - but I can't guarantee it's not a terrible idea.
I'm building an react app where I have a feed component and the feed component consists of array of post components. The post component contains a link in it for viewing the full post component. I'm not able to pass the respective props to the full post component. I'm not able to do a nested route for the fullpost component.
this is my layout component
import React, { Component } from "react";
import Header from "../Header/Header";
import classes from "./Layout.css";
import { Route, Switch } from "react-router-dom";
import FullPost from "../Feed/FullPost/FullPost";
import axios from "axios";
import Feed from "../Feed/Feed";
class Layout extends Component {
state = {
users: [],
};
componentDidMount() {
axios
.get("https://goodwill-60d8a.firebaseio.com/Users.json")
.then((response) => {
this.setState({ users: response.data });
});
}
render() {
console.log(this.state.users);
return (
<div className={classes.main}>
<div>
<Header />
</div>
<div className={classes.content}>
<Switch>
<Route
path="/"
exact
render={() => <Feed users={this.state.users} />}
/>
<Route path="/fullpost" exact render={() => <FullPost />} />
</Switch>
</div>
</div>
);
}
}
export default Layout;
FEED component
import React from "react";
import Post from "./Post/Post";
import classes from "./Feed.css";
const feed = (props) => {
const feedItems = Object.keys(props.users).map((key) => ({
id: key,
...props.users[key],
}));
return (
<div className={classes.feed}>
{feedItems.map((items) => (
<Post
key={items.id}
profilename={items.profileName}
profilepic={items.profilePic}
timestamp={items.timeStamp}
contentimage={items.contentImage}
contenttext={items.contentText}
trend={items.trend}
></Post>
))}
</div>
);
};
export default feed;
Post component
import React from "react";
import classes from "./Post.css";
import ShareButton from "../../UI/ShareButton/ShareButton";
import { Link } from "react-router-dom";
const post = (props) => {
return (
<div className={classes.post}>
<div className={classes.header}>
<div className={classes.profileimage}>
<img className={classes.pic} src={props.profilepic} alt="" />
</div>
<div className={classes.name}>{props.profilename}</div>
<div className={classes.timestamp}>{props.timestamp}</div>
</div>
<div className={classes.container}>
<div className={classes.image}>
<img src={props.contentimage} alt="" />
</div>
<div>
<div className={classes.text}>
<span>{props.contenttext}</span>
</div>
<div className={classes.fullpost}>
<Link to="/fullpost" {...props}>
See Full Post
</Link>
</div>
</div>
</div>
<div className={classes.footer}>
<div className={classes.trend}>
<span>{props.trend}</span>
</div>
<ShareButton />
</div>
</div>
);
};
export default post;
Full Post component
import React from "react";
import classes from "./FullPost.css";
import pic from "../../../Assets/Images/self.jpg";
import { Link } from "react-router-dom";
const fullPost = (props) => {
return (
<div className={classes.fullpost_container}>
<div className={classes.photo_container}>
<img src={props.profilepic} alt=" " />
</div>
<div className={classes.sidebar}>
<div className={classes.profileimage}>
<img src={props.profilePic} alt="" />
</div>
<div className={classes.profilename}>Tony Kroos</div>
<div className={classes.timestamp}>3 Hours Ago</div>
</div>
<div className={classes.feedlink}>
<Link to="/" className={classes.feedlink_text}>
See more posts
</Link>
</div>
</div>
);
};
export default fullPost;
Total Newbie in React and most of my learning is done through experimentation.
I have the following components:
App.js
import React, { Component } from 'react';
// Libraries and Utilities
import { BrowserRouter, Switch, Route } from 'react-router-dom';
// Components
import Layout from './components/layout/Layout';
import Home from './components/home/Home';
import Login from './components/login/Login';
class App extends Component {
static displayName = App.name;
render() {
return (
<BrowserRouter basename='/myapp>
<Layout>
<Switch>
<Route path="/" exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/admin' component={Admin} />
</Switch>
</Layout>
</BrowserRouter>
);
}
}
export default App;
Layout.js
import React, { Component } from 'react';
import NavMenu from '../navigation/NavMenu';
class Layout extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
<NavMenu />
</div>
<div className="main layout">
{this.props.children}
</div>
<div className="row">
<Footer />
</div>
</div>
);
}
};
export default Layout;
NavMenu.js
import React, { Component } from 'react';
import { NavLink } from "react-router-dom";
import logo from '../../assets/logo.svg';
class navigation extends Component {
constructor(props) {
super(props)
this.state = {
loggedIn: false
}
}
render() {
return (
<div className="row">
<nav className="navbar navbar-expand navbar-dark bg-primary fixed-top">
<a className="navbar-brand" href="/">
<img src={logo} width="250" height="70" alt="" />
</a>
<div className="collapse navbar-collapse">
<ul className="navbar-nav mr-auto">
<li className="nav-item" to={'/'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/'>Home</NavLink>
</li>
<li className="nav-item" to={'/admin1'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 1</NavLink>
</li>
<li className="nav-item" to={'/admin2'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 2</NavLink>
</li>
</ul>
<ul className="navbar-nav">
<li className="nav-item">
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/login'>
<i className="fa fa-sign-in" aria-hidden="true"></i>
</NavLink>
</li>
</ul>
</div>
</nav>
</div>
)
};
};
export default navigation;
Login .js
import React, { Component } from 'react';
class login extends Component {
constructor(props) {
super(props)
this.state = {
loginModel: {
UserName: '',
Password: ''
}
}
this.handleInputChange = this.handleInputChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleInputChange(event) {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState(prevState => ({
loginModel: {
...prevState.loginModel,
[name]: value
}
}))
}
handleSubmit(event) {
// At This Stage, I perform an API Call (via axios) and I get the Response Data.
const url = 'some url'
axios.post(url, this.state.loginModel).then((response) => {
if (response.status === 200) {
// Get token from response to be used in authenticated api calls.
const responseData = response.data
let authToken = responseData.token
console.log('authToken', authToken)
swal({
title: "My Application",
text: "Logon Successful.",
icon: "success"
}).then((value) => {
// Go to the Admin Home.
const path = '/admin'
this.props.history.push(path);
})
}
}, (err) => {
console.log(err.response)
const msg = err.response.data.message
const icon = err.response.data.icon
swal({
title: "My Application",
text: msg,
icon: icon
})
})
)
event.preventDefault();
}
componentDidMount() {
}
render() {
return (
<form className="form-signin" onSubmit={this.handleSubmit} >
<h3>Sign In</h3>
<div className="form-group">
<label>Username</label>
<input type="text" className="form-control" autoComplete="off"
id="input-username" name="UserName"
value={this.state.loginModel.UserName}
onChange={this.handleInputChange}
placeholder="Enter Username" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" autoComplete="off"
id="input-password" name="Password"
value={this.state.loginModel.Password}
onChange={this.handleInputChange}
placeholder="Enter Password" />
</div>
<button type="submit" className="btn btn-primary btn-block">Submit</button>
</form>
)
}
}
export default login;
Home.js
import React from 'react';
import { NavLink } from "react-router-dom";
const home = (props) => {
return (
<div className="container-fluid">
<div className="fill">
<div className="row">
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 1</h5>
<p className="card-text">
Details about Info 1
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-primary btn-block" to='/info1'>Start</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 2</h5>
<p className="card-text">
Details about Info 2
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-info btn-block" to='/info2'>Browse</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 3</h5>
<p className="card-text">
Details about Info 3
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-success btn-block" to='/info3'>View</NavLink>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default home;
My approach is quite simple. The application shows the Home component on initial load.
In the Navmenu, I have a link that navigates me to the Login screen.
In the Login screen, I have a login form where I am able to validate the user name and password via an API call.
I have multiple questions as I am still learning, but adding them here altogether as I feel it is all related.
Questions:
In my NavMenu component, I want to hide the admin1 and admin2 when on
initial load, and show it when the login is successful in the Login
component.
I want to prevent user from going to the route /admin1 and
/admin2 unless they are logged in. I am trying to read Protected
Routes but I am unable to get the hang of it as of yet.
In my Login screen, after successful login, one of the return value of the API
call is an API Key I can use for authorized calls. How can I make
that available such that I can access it from anywhere I perform an
API call.
I hope I provided enough context on what I am trying to achieve here. I know I need to brush up further my skills on how data communication between React happens.
Update: Been reading about Hooks, but I am unsure how to implement it here. Would I need to convert my JS files to use functional approach rather than class structure (ES6)?
Gracias.
I use redux for checking if use if logged in or not.
So when app start before show anything I check this.
and then I have privateRoute.
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function PrivateRoute({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin);
return (
<Route
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
{...props}
/>
);
}
export default PrivateRoute;
and define IsAuthenticated component to redirect home page if user is already logged in:
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function IsAuthenticated({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin)
return (
<Route
{...props}
render={props =>
!isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location }
}}
/>
)
}
/>
);
}
export default IsAuthenticated;
and define my routes here if user must authenticated to see them:
<Router>
<Switch>
{privateRoutes.map(({ path, component: Component }, idx) => (
<PrivateRoute
key={idx}
exact
path={path}
component={() => (
<SideNav>
<Component />
</SideNav>
)}
/>
))}
<IsAuthenticated exact path="/login" component={LoginPage} />
</Switch>
</Router>
here I use SideNav in my pages, you can use redux state in your Navbar component and with checking that you can show or hide whatever you want.
Or you can define two layout for your two types of your pages.
If you don't want to use redux, you can define state in App.js and pass it to your component or use react context.
I hope I helped you in your question.
I have this parent Component that simply renders a 'p' of the introduction text and a child component called 'PortfolioMenu'
import React from 'react'
import PortfolioMenu from './PortfolioMenu'
const Portfolio = () => {
return (
<div className="wrapper2">
<p>
Here is an Introduction text
</p>
<PortfolioMenu/>
</div>
)
}
export default Portfolio
Now in the child component 'PortfolioMenu', when I click on some link of NavLink I would like to make the 'p' of the parent component 'Portfolio' disappear. How can I solve it? Thank you
import React from 'react'
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import Houses from './Houses'
import Interiors from './Interiors'
const PortfolioMenu = () => {
return (
<div>
<Router>
<div class="wrapper2">
<div className="wrapper-portfolio">
<Route exact path='/portfolio/houses' render={() => <Houses />} />
<Route exact path='/portfolio/interiors' render={() =><Interiors/>}
/>
</div>
<nav>
<ul className="portfolio-menu">
<li><NavLink activeClassName="active" exact
to="/portfolio/houses">Houses</NavLink></li>
<li><NavLink activeClassName="active" exact
to="/portfolio/interiors">interiors</NavLink></li>
</ul>
</nav>
</div>
</Router>
</div>
)
}
export default PortfolioMenu
Here you go with a solution
import React from 'react'
import PortfolioMenu from './PortfolioMenu'
const Portfolio = () => {
constructor(props) {
super(props){
this.state = {
visibleP: true
};
}
this.handleMenuClick = this.handleMenuClick.bind(this);
}
handleMenuClick() {
this.setState({
visibleP: false
});
}
return (
<div className="wrapper2">
{
this.visibleP &&
<p>
Here is an Introduction text
</p>
}
<PortfolioMenu onHandleMenuClick={this.handleMenuClick}/>
</div>
)
}
import React from 'react'
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import Houses from './Houses'
import Interiors from './Interiors'
const PortfolioMenu = () => {
return (
<div>
<Router>
<div class="wrapper2">
<div className="wrapper-portfolio">
<Route exact path='/portfolio/houses' render={() => <Houses />} />
<Route exact path='/portfolio/interiors' render={() =><Interiors/>}
/>
</div>
<nav>
<ul className="portfolio-menu">
<li>
<NavLink
activeClassName="active"
exact
to="/portfolio/casas"
onClick={this.props.onHandleMenuClick()}
>
casas
</NavLink>
</li>
<li>
<NavLink
activeClassName="active"
exact
to="/portfolio/interiores"
onClick={this.props.onHandleMenuClick()}
>
interiores
</NavLink>
</li>
</ul>
</nav>
</div>
</Router>
</div>
)
}
PortfolioMenu.propTypes = {
onHandleMenuClick: PropTypes.func
};
export default PortfolioMenu;
You can't have a dump component. Here you need to pass props from child component to parent component.
I have a simple app with a home screen, a blog master list, and then blog detail page. Navigating from the home screen to the blog list and back works as expected. When I click on one of the blog posts the app navigates to the page and renders the blog post. But when I go back to the blog master list the blog post is now at the very bottom of the blog list. And if I then navigate back to the home page the same thing, the blog post is in the DOM behind the home page graphic.
I'm using react router 4.1.
Does it have to do with my route setup?
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import NavBar from './components/NavBar'
import Blog from './pages/blog'
import Home from './pages/home'
import Post from './pages/post'
import './css/App.css'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<NavBar />
<Route exact path='/' component={Home} />
<Route path='/blog' component={Blog} />
<Route path='/post/:slug' component={Post} />
</div>
</Router>
)
}
}
export default App
Or with my post component?
import React from 'react'
import fetch from 'isomorphic-unfetch'
import NavBar from '../components/NavBar'
import dateUtils from '../utilities/DateAndTime'
const classNames = require('classnames')
class Post extends React.Component {
constructor(props) {
super(props)
this.state = {
blogObject: null,
fetchBlogObject: false
}
this.fetchBlogObject = this.fetchBlogObject.bind(this)
this.createMarkup = this.createMarkup.bind(this)
this.assignStyleToCoverImage = this.assignStyleToCoverImage.bind(this)
this.formatDateString = this.formatDateString.bind(this)
}
componentWillMount() {
this.fetchBlogObject()
}
componentWillReceiveProps() {
this.fetchBlogObject()
}
fetchBlogObject() {
console.log('fetching')
this.setState({ fetchBlogObject: true })
fetch(`*******************`)
.then(response => response.json())
.then((responseJson) => {
console.log(responseJson)
this.setState({ blogObject: responseJson.object })
})
}
createMarkup(stringToConvertToHtml) {
return { __html: stringToConvertToHtml }
}
assignStyleToCoverImage() {
const style = {
background: `url(${this.state.blogObject.metadata.hero.url})`,
height: '35vh',
backgroundSize: 'cover',
backgroundPosition: 'center'
}
return style
}
formatDateString(dateString) {
console.log(dateString)
const d = `${dateUtils.returnMonthFromISODateString(dateString)} ${dateUtils.returnDateNumberFromISOString(dateString)}, ${dateUtils.returnFullYearFromISOString(dateString)} by Phil Andrews`
return d
}
render() {
const postContainerClasses = classNames({
'post-container': true
})
const postBodyClasses = classNames({
'post-body': true
})
return (
<div>
<NavBar />
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)
}
}
export default Post
Or with my blog list button action for navigating to a post page?
<Link id={this.props.blogObject.slug} to={`/post/${this.props.blogObject.slug}`}>
<button className='blog-button' style={buttonStyle} id={this.props.blogObject.slug} />
</Link>
I'm not sure why it would continue to render the entire component but if I get rid of the <NavBar /> in the post component the issue goes away.
Not working:
return (
<div>
<NavBar />
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)
Working:
return (
<div>
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)