How to Pass Props to a Component in React - reactjs

I have 2 page components with their own routes. There is one header component that is to be used in both pages, and it is supposed to change its content depending on what page you're on.
How can I change the content in the header per page?
return (
<main className={theme.main}>
<Header
title={this.state.headerTitle}
boldTitle={this.state.boldTitle}
/>
<div className={theme.content}>
<Switch>
<Route path={'/page1'} component={Page1} />
<Route path={'/page2'} component={Page2} />
</Switch>
</div>
<Footer/>
</main>
);
I am trying to pass props to the header in my Routes page as in the code below.
<Route path={'/page2'} component={Page2} currentTitle={this.state.headerTitle} />
UPDATE
I got it fixed this using the
import { withRouter } from "react-router"; and
export default withRouter(Header);
in Header Component then he listen the routes and I can put the pathname for to do what I need.
Then, I don't need set up state, just listen the routes inside that MyComponent.
Usign: this.props.location

MOVE YOUR HEADER INSIDE Page1 AND Page2.
<Route path={'/page2'} component={() => <Page2 currentTitle={this.state.headerTitle}
/>} />
Then in header use currentTitle to change title.

Put Header into its own component and import it separately into each page component.
Then you can pass props into the header like this, when you call the Header in each page...
import Header from (wherever that component is)
class Page# extends React.component {
other code
render() {
return (
<div>
<Header currentTitle="this.state.headerTitle" />
<rest of code for this page />
</div>
}
or whatever props you need.

I assume that the code you show lies inside the render() method of some React component, so that you have actually a state.
Note that the component attribute in the Route tag expects a value that is a function without arguments. The component to be rendered is the result of the function. But nothing forbids you to make some work before returning a value. I would try something like this
<Route path={'/page1'} component={() => {
this.setState({headerTitle: ...what you want..., boldTitle: ...what you want...})
return <Page1 />
}}/>
If Page1 is just a function, change the "return" line with return Page1()
Hope it helps - Carlos

you can use the redux library as global state
something like this
class Main extends Component{
render(){
return (
<main className={theme.main}>
<Header
title={this.props.headerTitle}
boldTitle={this.state.boldTitle}
/>
<div className={theme.content}>
<Switch>
<Route path={'/page1'} component={Page1}/>
<Route path={'/page2'}component={Page2}
/>
</Switch>
</div>
<Footer/>
</main>
)
}
const mapStateToProps = state =>{
return { headerTitle: state.headerTitle }
}
export default connect(mapStateToProps)(Main)
Page1
class Page1 extends Component{
changeTitle =()=>{
this.props.actions.changeTitle("title from Page1")
}
render(){
return (
<div>
<button onClick={this.changeTitle}>changeTitle</button>
</div>
)
}
const mapDispatchToProps = (dispatch)=> {
return {
actions: bindActionCreators({ changeTitle }, dispatch)
}
}
export default connect(null, mapDispatchToProps)(Page1)
the code it's not functional but this is an Idea how you can use redux for this purpose

Related

Effecting different component's state in React

I have two different components in React "Header" and "Main".
Header:
import React, { Component } from 'react'
import Logo from './HeaderComps/Logo'
import UserHeader from './HeaderComps/UserHeader'
export default class Header extends Component {
render() {
return (
<header>
<Logo />
<UserHeader name ="Boris"/>
</header>
)
}
}
Main:
export default class Main extends Component {
state ={isLogged : false}
handleClientFirstImpact = () =>{
if(this.state.isLogged === false){
return <Switch>
<Route exact path ='/registration' component={Register} />
<Route exact path ='/login' component={Login} />
</Switch>
}
}
render() {
return (
<Router>
<div className="Main">
{this.handleClientFirstImpact()}
</div>
</Router>
)
}
}
In "Main" I have two components "Register" and "Login".
How do I make Login page effect the Header's state? is there a React technology or a way to do that?
I want the "UserHeader" to show the User name but I don't know how to effect it's parent's state.
There might be some common component where you will be calling the Main as well as the Header Component. Suppose that component is App Component.
So inside App you have
render() {
return
<div>
<Header />
<Main />
</div>
}
Now what you can do is keep the userName in this App Component's state and this App Component will pass userName to the Component as :-
<Header userName={userName} />
Also pass a function as a prop to the Main Component which will enable the component to set the State of the Parent Component.
<Main setUserName={(newUserName) => this.setState(newUserName)} />
now this setUserName prop should be passed on to the components which are called via Route inside the Main Component. Keeping your example in mind (use render prop instead of component for Route):
export default class Main extends Component {
state ={isLogged : false}
handleClientFirstImpact = () =>{
const { setUserName } =this.props;
if(this.state.isLogged === false){
return
<Switch>
<Route exact path ='/registration'
render={(props) => <Register {...props} setUserName={setUserName} />}
/>
<Route exact path ='/login'
render={(props) => <Login {...props} setUserName={setUserName} />}
/>
</Switch>
}
}
render() {
return (
<Router>
<div className="Main">
{this.handleClientFirstImpact()}
</div>
</Router>
)
}
}
Now you have passed setUserName as a prop to both login and register and you can use this method to set App component's state which will in turn reflect the changes on the Header component.
Although the solution might work for you. I would advise you to simplify the Application layout. Keep the routing functionality in the main app Component. Use a separate layout component to render similar page layouts. It would avoid confusion in the long run.

How to change state based on Route change in React-Router?

I'm trying to figure out how to change the state of my Dashboard when a new route is clicked. This new route change needs to update the TopMenu component.
This is the code for the Dashboard
class Dashboard extends Component {
constructor (props) {
super(props)
this.state = {
selectedMenuItem: 'Now'
}
}
render () {
return (
<Router>
<div id='dashboard-container'>
<LeftMenu/>
<div className='column'>
<TopMenu selectedMenuItem={this.state.selectedMenuItem} />
<div id='content-container'>
<div>
<Switch>
<Route exact path='/' component={Now} />
<Route exact path='/surveys' component={Surveys} />
<Route exact path='/my-questions' />
<Route exact path='/feedback' />
<Route exact path='/logout' />
<Route render={function () {
return <p>Not Found</p>
}} />
</Switch>
</div>
</div>
</div>
</div>
</Router>
)}}
This is the code for the TopMenu
class TopMenu extends Component {
render () {
return (
<h3>{this.props.selectedMenuItem}</h3>
)
}
}
How do I listen to a change in React Router such that I can change the 'selectedMenuItem' state variable in the Dashboard and pass that to TopMenu.
Thanks!
Assuming you are using version 4, check the usage of match in React Router 4: https://reacttraining.com/react-router/web/api/match
match will include all the path information you will need to handle route changes. You can access it by calling this.props.match in your top level page component.
I had the same problem and I solved it with withRouter which is build for integrate router with redux, the only thing you need to do is wrap your connect with withRouter. for more information read redux integration document

How to hide header component in login page reactJS

Am new to ReactJS. I want to hide header component in Login page and show in inner pages. I have an App.js I have used ternary operator but not working.
class App extends Component {
render(){
let HideHeader = EmployeeLogin ? null : <HeaderNavContainer />
return (
<div>
<Router history={history}>
<div>
{HideHeader}
<Switch>
<Route path="/about" component={About} />
<Route path="/EmployeeLogin" component={EmployeeLogin} />
<Route path="/MyPreferences" component={MyPreferences} />
<Route component={PageNotFound} />
</Switch>
</div>
</Router>
</div>
);
}
}
If EmployeeLogin component is rendered I want to hide header navigation
<HeaderNavContainer /> if not I want to show <HeaderNavContainer />
In the render method of your HeaderNavContainer, you can do this:
render() {
if (window.location.pathname === '/EmployeeLogin') return null;
return <insert your header nav code>;
}
Since HeaderNavContainer is wrapped within <Router>, it'll re-render when window.location.pathname changes.
Alternatively, add HeaderNavContainer to your About, MyPreferences etc instead of putting in App.
In component you can check if the history.location.pathname is equal to /EmployeeLogin and then return null. You can use withReducer for getting history object as a prop.
render(){
if(this.props.history.location.pathname==='/EmployeeLogin'){
return null;
}
return (//your navigation component code.)
}
Instead of checking component exists or not try to check the URL is hit or not
In window.location.pathname you will get the current URL.
let HideHeader = window.location.pathname === 'your need string' ? null :
Create a HideHeader route that renders (conditionally) the Header component and an Outlet component for the nested route components.
import { Outlet, useLocation } from "react-router-dom";
import { Header } from "./Header";
const HideHeader = ({ hideHeaderPaths }) => {
const { pathName } = useLocation();
return (
<>
{!hideHeaderPaths.includes(pathName) && <Header />}
<Outlet />
</>
);
};
export default HideHeader;
In App.js
import your HideHeader.js
import HideHeader from "./common/HideHeader"
...
...
<Route element={<HideHeader hideHeaderPaths={["/login"]} />}></Route>
and import your header on those pages where you want to show
<Header />

Link page bounded click handlers to Footer component

Right now I have a Footer component with three different buttons. The onClick of two of those buttons depends on the page, and are defined in those pages. Currently I render the Footer component in the Page components separately, where the onClick functions are defined and handed as a prop, and is working great.
However I added the CSS element max-width to the pages, and is affecting the Footer too, which I don't want.
To solve this I need to render the Footer outside of the Page components, and in the Router component, just like the Header. But the issue is that I don't know how to link the click handlers of those two Footer buttons, which are defined in the Page components.
What would be the best way to solve this? Push the onClick functions in my Redux store?
Currently it's working like this:
Router.js
<div id="router-container">
<Header />
<Switch>
<Route path="/dashboard" component={DashboardPage} />
<Route path="/settings" component={SettingsPage} />
</Switch>
</div>
DashboardPage.js
const DashboardPage = () => (
<div id="dashboard-page">
...content
<Footer onRightButtonClick={myDashboardPageClickHandler} />
</div>
);
SettingsPage.js
const SettingsPage = () => (
<div id="settings-page">
...content
<Footer onRightButtonClick={mySettingsPageClickHandler} />
</div>
);
But how can I get it to work like this:
Router.js (new)
<div id="router-container">
<Header />
<Switch>
<Route path="/dashboard" component={DashboardPage} />
<Route path="/settings" component={SettingsPage} />
</Switch>
<Footer />
</div>
DashboardPage.js / SettingsPage.js
const DashboardPage = () => {
// set the onClick of the footer somehow to myDashboardPageClickHandler()
return (
<div id="dashboard-page">
...content
</div>
);
};
I would recommend using the withRouter function of React Router to transform the Footer, like so:
const FooterWithRouter = withRouter(Footer);
then, inside the Footer component, define functions like so:
handleRightButtonClick() {
const pathname = { this.props.location };
if ( pathname === '/dashboard' ) {
return myDashboardPageClickHandler;
} else if ( pathname === '/settings' ) {
return mySettingsPageClickHandler;
}
}
and assign the onClick of the button to the return value of this function, like so:
<button class="right-arrow" onClick={handleRightButtonClick()}></button>
See if this works.

React router 4 not updating when using children prop on history.push

I have this piece of code:
class Base extends Component {
changeRoute = () => {
// after this, address bar gets updated but I can't see the Users
// component, only Home component.
this.props.history.push('/users');
}
render() {
return (
<div>
<MyBar />
{this.props.children}
</div>
)
}
}
class App extends Component {
render() {
return (
<Router>
<Base>
<a onClick={this.changeRoute}>Change</a>
<Route path="/home" component={Home} />
<Route path="/users" component={Users} />
</Base>
</Router>
)
}
}
However, when I try to change location by either using history.push or push from react-router-redux I can see the browser path updated but the content is not updating, it shows the original path content. I also noted that whenever I refresh the browser I can see the correct content related to the path.
When I change the code to the following, both the browser path and the content updates accordingly as expected, my question is: Why is it behaving different? if in my opinion both codes do the same thing.
class Base extends Component {
render() {
return (
<MyBar />
)
}
}
class App extends Component {
changeRoute = () => {
// after this, address bar and component are updated as expected.
this.props.history.push('/users');
}
render() {
return (
<Router>
<div>
<Base />
<a onClick={this.changeRoute}>Change</a>
<Route path="/home" component={Home} />
<Route path="/users" component={Users} />
</div>
</Router>
)
}
}
Edit:
I added to the source code the push method. This is the piece of code I'm using to export the App component:
import {withRouter} from 'react-router';
export default withRouter(App);
This is the code I ran and it is running fine. Can you please check whether there is anything I need to change in my code to reproduce your issue?
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink, BrowserRouter,Route} from 'react-router-dom';
class Base extends React.Component {
render() {
return (
<div>
<div>MyBar</div>
{this.props.children}
</div>
)
}
}
class App extends React.Component {
render() {
return (
<BrowserRouter>
<Base>
<NavLink to="/users">Change</NavLink>
<Route path="/home" render={()=>"Home"} />
<Route path="/users" render={()=>"Users"} />
</Base>
</BrowserRouter>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Edit: From what I understood, you want to be able to navigate to the user page when the change link is clicked. The correct way to do it is using the NavLink control. This would not require the use of withRouter HOC which should only be used inside a Router component and not outside it.

Resources