Im new to react and im having issues with the routing. I want the navbar to render on some pages but not others.What is the correct way to do this? I know im not supposed to render it in specific components.
so if this is my app.js
var App = React.createClass ({
render (){
return (
<div>
<NavbarInstance />
</div>
);
}
});
document.write('<div id="container"></div>');
ReactDom.render(
<Router history={createHistory({ queryKey: false })}
onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" component={App} />
<Route path="/login" component={LoginForm} />
<Route path="/other" component={Other} />
</Router>,
document.getElementById('container')
);
and this is my login page(see navbar instance-incorrect)
import React from 'react';
import Input from 'react-bootstrap/lib/Input';
import NavbarInstance from './components/header.jsx';
const LoginForm = React.createClass({
getInitialState: function() {
return {
username:'',
password:''
}
},
render () {
return (
<div>
<NavbarInstance />
<div className = "col-sm-12">
<h3> Log In </h3>
</div>
<div className ="col-sm-6">
<Input type = "text"
placeholder ="Username"
/>
<Input type= "password"
placeholder="Password"
/>
</div>
</div>
)
}
})
export default LoginForm
One option would be to keep track of what page you are in within a state variable within your main App component. Then add a check (say you didn't want to render it if page is 'index'.
return (
{ if (this.state.page !== 'index')
return <NavbarInstance />
}
)
Related
I want to create a login page. When the user submits the form, the username should be rendered on the dashboard. I am unable to figure that out.
import React from "react";
import Footer from "./Footer";
import Back from "./Back";
import { Link } from "react-router-dom";
const Login = () => {
return (
<div>
<Back />
<div>
<form className="login-form">
<h1 className="form-heading">Login</h1>
<input
className="form-input"
type="text"
placeholder="Enter your Username"
/>
<input
className="form-input"
type="password"
placeholder="Enter your password"
/>
<button className="form-button">
<Link to={"/dashboard"}>Login</Link>
</button>
</form>
</div>
<Footer />
</div>
);
};
export default Login;
To share data between two components, the standard react approach is to lift the state up to a parent component, then pass it down (through props or context). For example:
const App = () => {
const [user, setUser] = useState();
return (
<Routes>
<Route path="/login" element={<Login setUser={setUser}/>}
<Route path="/dashboard" element={<Dashboard user={user}/>}
</Routes>
)
}
const Login = ({ setUser }) => {
return (
// ...
<Link to="/dashboard" onClick={() => setUser('bob')}
// ...
);
}
const Dashboard = ({ user }) => {
return (
<div>
Hello {user}!
</div>
)
}
The main problem is that this image is selected from the file explorer and I am using react-router.
Add.js
this is where you select the image
import { Link } from "react-router-dom";
import About from "./About";
import './styles/modal.css'
import firebase from "firebase";
require("firebase/firestore")
require("firebase/storage")
export default function Add(props) {
const [image, setImage] = useState(null);
const [modal, setModal] = useState(false);
const pickImage = (event) => {
//console.log();
setImage(URL.createObjectURL(event.target.files[0]));
//console.log(image);
}
const toggle = () => {
setModal(!modal);
}
return (
<div>
<h1>Add</h1>
<button onClick={toggle}>Add image</button>
{modal ? (
<div className="modal-bg">
<div className="modal">
<img src={image} style={{ width: '60%', height: '60%' }} className="ex-img" />
<br /><br />
<label htmlFor="fie" className="gcoo btn-default">+ File
<input id="fie" type="file" onChange={pickImage} className="file-pick" />
</label>
<br />
<br />
<div className="bottom-buttons">
<Link to="/about">
<button className="save">Save</button>
</Link>
<button onClick={() => setModal(false)} className="closse">Close</button>
</div>
</div>
</div>
) : null}
</div>
)
}
I am using firebase but not in this file so you can ignore this.
MainRoutes.js
this is where all the routes and pages are.
import { Route } from "react-router";
import { Switch } from 'react-router-dom';
import ImageDisplay from "./components/ImageDisplay";
import Add from './components/Add';
export default function MainRoute(props) {
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay />} />
<Route exact path="/add" component={() => <Add />} />
</Switch>
);
}
finally this file ImageDisplay.js is where the image should be displayed
I dont have much on this file because i dont know how to put in any images.
I have tried props but whenever i imported the Imagedisplay it always showed the content on it and i dont want anything from image display. I only want to send an image over there.
import React from 'react'
import { Link } from "react-router-dom"
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img />
<p></p>
</div>
</div>
)
}
export default ImageDisplay;
Make sure that you are not reloading the page when moving between the two routes, since this will remove all state.
To share state between the two components you would need to store the state in the parent, and pass it to the children.
Add:
export default function Add(props) {
const pickImage = (event) => {
props.setImage(URL.createObjectURL(event.target.files[0]));
}
// The rest of your function
}
And in your parent:
export default function MainRoute(props) {
const [image, setImage] = useState(null)
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay image={image} />} />
<Route exact path="/add" component={() => <Add setImage={setImage} />} />
</Switch>
);
}
You can now access the image prop in your imageDisplay.
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img src={props.image} />
<p></p>
</div>
</div>
)
}
I am implementing the global navigation sidebar (left collapsible) with react but I want to exclude or hide my sidebar from some routes or components.
and when I importing it to a particular component I am loosing my component responsiveness.
import React from "react";
//more imports are here
const App = () => (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
<SideBar>
<Route path="/" exact component={Home} />
<Route path="/setting" component={Setting} />
<Route path="/help" component={Help} />
<Route path="/about" component={About} />
</SideBar>
</div>
</div>
</ThemeProvider>
);
export default App;
Looking for the solution to hide the sidebar from Route path="/" exact component={Home} /> route.
or is there any other way to achieve the same functionality.
Looks like the routes need to be taken out from the SideBar JSX first so that routes won't be wrapped inside SideBar indefinitely.
Pass a function props to the route components which can change the state of parent component's sidebar. Then at the route where you want to hide sidebar, call that function which will take the SideBar JSX out from the DOM.
Example:
import React from "react";
//more imports are here
const App = () => {
const [showSidebar,setShowSidebar] = React.useState();
const handleToggleSideBar = () => {
//togglesidebar with useState
setShowSidebar(!showSidebar);
}
return (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
{showSidebar && <SideBar />}
<Route path="/" exact render={(props) => <Home toggleSideBar={handleToggleSideBar } {...props} />} />
<Route path="/setting" render={//do the same thing like Home} />
</div>
</div>
</ThemeProvider>
)};
export default App;
Home.jsx
export const Home = ({toggleSideBar}) => {
useEffect(() => {
toggleSideBar();
},[]);
}
Hello community :) My first Q here.
(There were couple of similar questions but they didn't answer my particular code issue and I tried them to apply but without success.)
So I would like to render the child component in nested route without the parent one showing in the view
See the picture at the end --->
import React from 'react';
import {BrowserRouter, Route, Switch, Link} from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.min.css';
import Routing from "./components/Routings";
export default class Browserrouting extends React.Component {
render () {
return (
<BrowserRouter>
<Routing/>
</BrowserRouter>
)
}
}
Here is the Routing component :
import About from "../views/About";
import HomeBackground from "../views/Background";
import ShelterApp from '../views/ShelterApp';
export default (props) => (
<div className="flexColumn">
<div> <ul className="flexRow center">
<li className="homeLink"><Link className="colorBrown" to="/">Home</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/shelterApp">Shelter App</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/about">About our site and shelter</Link></li>
</ul></div>
<Switch>
<Route exact path="/" component={() => <HomeBackground />} />
<Route path="/about" component={() => <About />} />
<Route path="/shelterApp" component={() => <ShelterApp />} />
</Switch>
</div>
)
And in ShelterApp component I have some text and imported another component which contains the links and nested routes I would like to display without showing the parent component ShelterApp:
class ShelterApp extends React.Component {
render() {
return (
<div className="flex center">
<div className="card center" style={{ "width": "25em", "height":"25em" }}>
<div className="card-body textCenter">
<h5 className="card-title paddingTitle">Welcome to our site</h5>
<h6 className="card-subtitle mb-2 text-muted"> Login or register if it's your first time</h6>
</div>
<LoginRouting match={this.props.match} />
</div>
</div>)
}
}
export default ShelterApp;
and the final child componet with the "lowest" routes in hierarchy :
class LoginRouting extends React.Component {
constructor(props) {
super(props)
this.state = {
users: []
}
}
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return (
<div >
<div className="flexRow center">
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/login">Login form</Link>} />
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/register">Register form</Link>} />
</div>
<div>
<Route path="/shelterApp/login" render={() => <Login />} />
<Route path="/shelterApp/register" render={() => <Register />} />
</div>
</div>
)
}
}
export default withRouter( LoginRouting)
enter image description here
IMAGE with the view :
I will be thankful for any advises !
On your ShelterApp component you can create a new state called hideInfo, or something, that tracks if the user clicked on "Login form" or "Register form".
Then you can pass a props to your <LoginRouting> component.
When the user clicks on "Login form" or "Register form" you change this.hideInfo.
<LoginRouting
onShowForm={() => this.setState({ hideInfo: !hideInfo})}
match={this.props.match}
/>
Once I started passing props from parent to child to child I have been getting this problem where the getQuestion function only gets me the first letter typed, In addition in the input field nothing shows up.
Before when my code was just Parent to child it worked.
I want to know what exactly is going on because I have tried debugging by console logging and all I know is certain is that it only registers the first letter.
This question did not help because I have not misspelled onChange.
Can't type in React input text field
App.js
class App extends Component {
constructor(props){
super(props);
this.getPostId = this.getPostId.bind(this);
this.getQuestion = this.getQuestion.bind(this);
this.makePost = this.makePost.bind(this);
this.getBody = this.getBody.bind(this);
this.getPostType = this.getPostType.bind(this);
this.getImgSrc = this.getImgSrc.bind(this);
this.submitPost = this.submitPost.bind(this);
this.formOpen = this.formOpen.bind(this);
this.formClose = this.formClose.bind(this);
this.back = this.back.bind(this);
this.showPost = this.showPost.bind(this);
this.renderPosts = this.renderPosts.bind(this);
//Answer/Response methods
this.makeAnswer = this.makeAnswer.bind(this);
this.getAnswer = this.getAnswer.bind(this);
this.submitAnswer = this.submitAnswer.bind(this);
this.state = {
posts: [],
answers: [],
question: '',
body: '',
postType: 'Question',
imgSrc: '',
form: false,
openedPost: null,
answer: '',
favorited: false,
//sign up
email:'',
password: '',
user: null
}
}
getQuestion(event) {
event.preventDefault();
this.setState({ question:event.target.value });
}
render() {
return (
<Router>
<div className="container">
<Route
exact path={"/"}
component={() => <Home />}
/>
<Route
exact path={"/home"}
component={() => <Home />}
/>
<Route
exact path={"/signup"}
component={() => <SignUp />}
/>
<Route
exact path={`/dashboard`}
component={() =>
<Dashboard back={this.back}
form={this.state.form}
openedPost={this.state.openedPost}
renderPosts={this.renderPosts}
formClose={this.formClose}
formOpen={this.formOpen}
posts={this.state.posts}
getPostId={this.getPostId}
getQuestion={this.getQuestion}
makePost={this.makePost}
getBody={this.getBody}
getPostType={this.getPostType}
getImgSrc={this.getImgSrc}
submitPost={this.submitPost}
test={this.test}
question={this.state.question}
/>}
/>
<Route
exact path={`/dashboard/post${this.state.openedPost}`}
component={() =>
<SinglePost posts={this.state.posts}
openedPost={this.state.openedPost}
getAnswer={this.getAnswer}
makeAnswer={this.makeAnswer}
submitAnswer={this.submitAnswer}
showAnswers={this.showAnswers}
renderAnswers={this.renderAnswers}
renderFavorite={this.renderFavorite}
userFavorited={this.userFavorited}
back={this.back}
/>
}
/>
</div>
</Router>
);
}
Dashboard.js
import React, { Component } from 'react';
import Navagationbar from '../../components/Navigation/Navagationbar';
import Header from '../../components/Header/Header';
import SignUpButton from '../../components/SignUp/SignUpButton';
import AddPostForm from './AddPostForm';
import './styles.css';
import {
Link
} from 'react-router-dom'
class Dashboard extends Component {
render() {
let renderedPosts = null;
let createPostButton = <div className="container" ><button className="button-primary" onClick={this.props.formOpen}> Create Post </button> </div>;
if(this.props.openedPost) {
renderedPosts = null;
createPostButton = null;
}
else {
renderedPosts = this.props.renderPosts();
}
let createPostForm = null;
const openedForm = this.props.form;
if(openedForm) {
createPostForm =
<AddPostForm
formClose={this.props.formClose}
posts={this.props.posts}
getPostId={this.props.getPostId}
getQuestion={this.props.getQuestion}
makePost={this.props.makePost}
getBody={this.props.getBody}
getPostType={this.props.getPostType}
getImgSrc={this.props.getImgSrc}
submitPost={this.props.submitPost}
question={this.props.question}
/>
createPostButton = null;
}
console.log("OPENED FORM IS " + openedForm)
return (
<div >
<SignUpButton />
<Header />
<button onClick={this.props.test}/>
{this.props.openedPost ? null : <Navagationbar />}
{createPostForm}
<div className="row">
<div>
{createPostButton}
</div>
</div>
<div className="row">
</div>
<div className="row">
<div className="twelve columns">
{renderedPosts}
</div>
</div>
</div>
);
}
}
export default Dashboard;
AddPostForm.js
import React, { Component } from 'react';
import './styles.css';
class AddPostForm extends Component {
render() {
return(
<div className="container">
<div className="row">
<div className="six columns">
<label>Post Title</label>
<input onChange={this.props.getQuestion} value={this.props.question} className="u-full-width" type="search" placeholder="title" id="exampleEmailInput"/>
</div>
<div className="six columns">
<label>Post Type</label>
<select value={this.props.type} onChange={this.props.getPostType} className="u-full-width">
<option value="Question">Question</option>
<option value="Discussion">Discussion</option>
</select>
</div>
</div>
<div className="row">
<div className="twelve columns">
<label>Post</label>
<textarea onChange={this.props.getBody} className="u-full-width" placeholder="get some clout" id="postMessage"></textarea>
<label>
<span>Image Link</span> <br />
<input type="search" onChange={this.props.getImgSrc}/>
</label>
<input className="button-primary" type="button" value="submit" onClick={this.props.submitPost}/>
<button onClick={this.props.formClose}>Cancel </button>
</div>
</div>
</div>
);
}
}
export default AddPostForm;
edit:
After removing event.preventDefault() from getQuestion I can type but why does the input field unfocus after typing a single letter.
Is it because after every time I type the input field re-renders?
edit: Added majority of the code as requested.
This is sufficient in my opinion let me know if you want the rest of the functions.
Having gone through the code, I noticed all methods come from the root level component App. In which case when you type in the post title input field it immediately calls the parent getQuestion method which set state there by causing a re-render of the page which in turn causing the input field to lose focus.
Method 1:
To fix this I'd suggest you maintain state for the AddPostForm by allowing it manage its own state.
import React, { Component } from 'react';
class AddPostForm extends Component {
state = {
question: ""
}
setQuestion = (event) => {
this.setState({
question: event.target.value
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="six columns">
<label>Post Title</label>
<input
onChange={this.setQuestion} // note change
value={this.state.question} // note change
className="u-full-width"
type="search"
placeholder="title"
id="exampleEmailInput"
/>
</div>
...
</div>
</div>
);
}
}
export default AddPostForm;
Method 2:
In App.js render method I made few changes that will allow you pass down props to the child components without the text fields loosing focus.
render() {
return (
<Router>
<div className="container">
<Route
exact
path="/"
component={Home}
/>
<Route
exact
path="/home"
component={Home}
/>
<Route
exact
path="/signup"
component={SignUp}
/>
<Route
exact
path="/dashboard"
render={(props) =>
<Dashboard
{...props}
back={this.back}
body={this.state.body}
form={this.state.form}
openedPost={this.state.openedPost}
renderPosts={this.renderPosts}
formClose={this.formClose}
formOpen={this.formOpen}
posts={this.state.posts}
getPostId={this.getPostId}
getQuestion={this.getQuestion}
makePost={this.makePost}
getBody={this.getBody}
getPostType={this.getPostType}
getImgSrc={this.getImgSrc}
submitPost={this.submitPost}
test={this.test}
question={this.state.question}
/>
}
/>
<Route
exact
path={`/dashboard/post${this.state.openedPost}`}
render={(props) =>
<SinglePost
{...props}
posts={this.state.posts}
openedPost={this.state.openedPost}
getAnswer={this.getAnswer}
makeAnswer={this.makeAnswer}
submitAnswer={this.submitAnswer}
showAnswers={this.showAnswers}
renderAnswers={this.renderAnswers}
renderFavorite={this.renderFavorite}
userFavorited={this.userFavorited}
back={this.back}
/>
}
/>
</div>
</Router>
);
}
In the Routes for dashboard I changed from using component prop of Route to using render prop instead. This fixes the issue.
To improve it you can clear the form after the state data is send to the parent component.
handleChange(e) {
let { name, value } = e.target;
// clone current state
let clonedState = Object.assign({}, this.state);
clonedState.data[name] = value;
this.setState({
data: clonedState.data,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.getQuestion(this.state.data)
// clear state data
this.setState({ data: {} });
}
It would be better to track changes in the component the user is actually typing in. Then onSubmit, call your getQuestion(this.state).
This would be in any form component a user is typing in.
handleChange(e) {
let { name, value } = e.target;
this.setState({
[name]: value,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.getQuestion(this.state)
}