React NavBar Component Prevent render - javascript

I am a new in React world in want to now why this code is always render every time i made a change on the page it always render the components that is no change made, for example:
<Grid columns="equal" className="app" style={{ background: secondaryColor.hex }}>
<ColorPanel
key={currentUser && currentUser.name}
currentUser={currentUser}
/>
<SidePanel
key={currentUser && currentUser.uid}
currentUser={currentUser}
primaryColor={primaryColor}
/>
<Grid.Column style={{ marginLeft: 320 }}>
<Messages
key={currentChannel && currentChannel.id}
currentChannel={currentChannel}
currentUser={currentUser}
isPrivateChannel={isPrivateChannel}
/>
</Grid.Column>
<Grid.Column width={4}>
<MetaPanel
key={currentChannel && currentChannel.name}
userPost={userPost}
currentChannel={currentChannel}
isPrivateChannel={isPrivateChannel}
/>
</Grid.Column>
</Grid>
I made a change on the MessagePanel component and the entiry app render again.

Hi can you test with the React Pure component class and React.memo functions, those functions help you to prevent re-render on the React components for example: If you have a class component you extends from PureComponent besides Components Pure component class do a shallow validation on the props of the component if a change is between the props the component is render againg, the same behavior is with the React.memo the only thing is the last one if for functional component here are the links of the React documentation:
React.memo example:
const NavMemo = React.memo(({ activeTab, onTabChange }) => {
console.log('Render');
return (
<nav className="App-nav">
<ul>
<li className={`App-nav-item ${activeTab === 0 && 'selected'}`}>
<a onClick={() => onTabChange(0)}>Items</a>
</li>
<li className={`App-nav-item ${activeTab === 1 && 'selected'}`}>
<a onClick={() => onTabChange(1)}>Cart</a>
</li>
</ul>
</nav>
);
});
React Pure Component Example:
export default class Nav extends React.PureComponent {
render() {
const { onTabChange, activeTab } = this.props;
return (
<nav className="App-nav">
<ul>
<li className={`App-nav-item ${activeTab === 0 && 'selected'}`}>
<a onClick={() => onTabChange(0)}>Items</a>
</li>
<li className={`App-nav-item ${activeTab === 1 && 'selected'}`}>
<a onClick={() => onTabChange(1)}>Cart</a>
</li>
</ul>
</nav>
);
}
}
https://reactjs.org/docs/react-api.html#reactmemo
https://reactjs.org/docs/react-api.html#reactpurecomponent

Related

NavLink Active property does not work with nested pages

I am using Reactjs in my project. NavLink active property does not work with nested pages inside the same tab?? It works just in the main tab anything inside the main tab does not work with. I want the white border appear in the main tab while open any pages inside it.
import { NavLink } from "react-router-dom";
function Navbar() {
let activeStyle = {
border: "solid 3px #FFF",
};
return (
<>
<nav className="navbar">
<ul className="nav-items">
{navItems.map((item) => {
if (item.id === "3") {
return (
<li
key={item.id}
className={item.cName}
onMouseClick={() => setDropdown(true)}
onMouseEnter={() => setDropdown(true)}
onMouseLeave={() => setDropdown(false)}
>
<NavLink to={item.title}
style={({ isActive }) =>
isActive ? activeStyle: undefined
}
>{item.title}</NavLink>
{dropdown && <Dropdown />}
</li>
);
}
return (
<li key={item.id}
className={item.cName}>
<NavLink to={item.path}
style={({ isActive }) =>
isActive ? activeStyle: undefined
}>{item.title}</NavLink>
</li>
);
})}
</ul>
</nav>
</>
);
}
export default Navbar;

How to rerender unrelated components when a dropdown changes its selected value in react.js

I have a dropdown list that contains account names and accounts Ids. The dropdown is a child that lives in my NavMenu.js titled AccountsDropdown
render () {
return (
<header>
<Navbar className="navbar-expand-sm navbar-toggleable-sm ng-white border-bottom box-shadow mb-3" light>
<Container>
<div><NavbarBrand className="brand-name" tag={Link} to="/">PABST</NavbarBrand><br />
<NavbarText className="sub-headline" to="/">Budget Allocation & Forecasting</NavbarText></div>
<NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
<AccountsDropdown></AccountsDropdown>
<Collapse className="d-sm-inline-flex flex-sm-row-reverse center-align-flex margin-right" isOpen={!this.state.collapsed} navbar>
<ul className="navbar-nav flex-grow">
<NavItem>
<NavLink tag={Link} id={"budgetplanner"} onClick={() => this.handleChange("budgetplanner")} className={"budgetplanner" === this.state.selectedNavItem ? "active" : "inactive"} to="/"><EventNoteIcon ></EventNoteIcon>Budget Planner</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} id={"budgetresults"} onClick={() => this.handleChange("budgetresults")} className={"budgetresults" === this.state.selectedNavItem ? "active" : "inactive"} to="/budget-results"><PieChartRoundedIcon></PieChartRoundedIcon>Budget Results</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} id={"docs"} onClick={() => this.handleChange("docs")} className={"docs" === this.state.selectedNavItem ? "active" : "inactive"} to="/fetch-data"><FolderRoundedIcon></FolderRoundedIcon>Docs</NavLink>
</NavItem>
</ul>
</Collapse>
This menu as you can see also has redirects to my other JSX pages. So for example, when a user clicks on Budget Results, they get redirected to the Budget Results page. This Budget Results page is a top level parent. It is not a child of any other component. Here is the code:
import React, { Component } from 'react';
import MainGridComponent from './MainGridComponent';
import '../css/main.css';
export class BudgetResults extends Component {
static displayName = BudgetResults.name;
constructor(props) {
super(props);
this.state = {
accountid: "1"
};
}
render() {
return(
<div className="row">
<div className="col-md-8 budget-results">
<span className="grid-header">Recent Budget Output</span>
<MainGridComponent accountid={this.state.accountid} pagetype="BudgetResults"></MainGridComponent>
</div>
</div>
);
}
}
export default BudgetResults
As you can see, AccountsDropdown and BudgetResults are entirely unrelated. My question is, is it possible to cause a rerender on BudgetResults when AccountsDropdown changes its state? Is this something that's only possible with Redux?
Redux is not compulsory to achieve this.
Add a common ancestor to BudgetResults & AccountsDropdown.
Move the state up to this ancestor.
Then you can use either prop callbacks or the Context API to achieve it.

How to import parameters from one React component to another

Please apologize my lack of knowledge but I'm new to React and JavaScript.
I'm building a Website where I have a Sidebar and a Navbar on top of the page. The Sidebar is activated / deactivated via an hamburger menu which is located in the Navbar-component. It is activated via CSS-classes: <nav className={isActive ? 'nav-menu active' : 'nav-menu'}>
My Problem now is, that I dont know how to transfer the variables toggleButton and isActive from the Navbar.jsx where they are declared to the Sidebar.jsx where I need them to activate my Sidebar.
Do I need to import the js files? Is it possible to export isActive and toggleButton seperatly from the JSX-Code?
Thanks for your help! :)
This is my Code:
Navbar-component
import React from "react";
import Navbar from "react-bootstrap/Navbar";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import Nav from "react-bootstrap/Nav";
import FormControl from "react-bootstrap/Form";
import Dropdown from "react-bootstrap/Dropdown";
import './Navbar.css';
const NavbarTop = () => {
const [isActive, setIsActive] = useState(false)
const toggleButton = useCallback(
() => setIsActive(prevState => !prevState),
[],
);
return (
<>
<Navbar className="background-color" variant="light">
<Navbar.Brand href="#home">
<img
src="https://pbs.twimg.com/profile_images/603568605796634624/Nq0nXZZA_400x400.jpg"
width="30"
height="30"
className="d-inline-block align-top"
alt="React Bootstrap logo"
/>
</Navbar.Brand>
<Dropdown>
<Dropdown.Toggle Classname="color" rvariant="success" id="dropdown-basic">
Kategorien
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#/action-1">Bücher</Dropdown.Item>
<Dropdown.Item href="#/action-2">Veranstaltungen</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item href="#/action-3">Etwas Posten</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Form inline>
<FormControl type="text" placeholder="Search" className="mr-sm-2" />
<Button variant="outline-primary">Search</Button>
</Form>
<Link to='#' className='menu-bars'>
<HamburgerSpring className="Hamburger"
buttonColor="transparent"
barColor="#007466"
buttonWidth={35}
{...{ isActive, toggleButton }}
/>
</Link>
</Animate>
</Navbar>
</>
);
};
export default NavbarTop;
Sidebar-component:
import React, { useState, useCallback } from 'react';
import { Link } from 'react-router-dom';
import { SidebarData } from './SidebarData';
import { IconContext } from 'react-icons';
import {Animate} from 'react-rebound';
import { HamburgerSpring } from 'react-animated-burgers';
import './Sidebar.css';
function Sidebar(isActive, toggleButton) {
return (
<>
<IconContext.Provider value={{ color: 'white' }}>
<nav className={isActive ? 'nav-menu active' : 'nav-menu'}>
<div className='nav-menu-items'>
<ul onClick={toggleButton}>
{SidebarData.map((item, index) => {
return (
<li key={index} className={item.cName}>
<Link to={item.path}>
{item.icon}
<span>{item.title}</span>
</Link>
</li>
);
})}
</ul>
</div>
</nav>
</IconContext.Provider>
</>
);
}
export default Sidebar;
One possible approach is to move the state one level up.
const ParentComponent = () => {
const [isActive, setIsActive] = useState(false)
const toggleButton = useCallback(
() => setIsActive(prevState => !prevState),
[],
);
.....
.....
{/* You can use like this */}
<SideBar isActive={isActive} toggleButton={toggleButton} />
<NavBar isActive={isActive} toggleButton={toggleButton} />
}
Alternatively, you can use the context API to store to hold the state and access it anywhere within the app. In your case, I think the first option is a better idea given it's simple nature.
This is where you'd lift state up, outside of those into a container of sorts.
function Container() {
const [toggleIsActive, setToggleIsActive] = useState(false);
return (
<Navbar ... toggleIsActive={toggleIsActive} setToggleIsActive={setToggleIsActive} />
<Sidebar ... toggleIsActive={toggleIsActive} setToggleIsActive={setToggleIsActive} />
)
}
Essentially you track that from higher up in the tree while providing the values/methods for changing to the children components.

How do I save the layout to state each time it re-renders?

I am working on an application that changes the order of a product grid by rearranging tiles. (It is like Packery). I have a renderData function that populates the layout grid with data from a file input. That is working fine. The part that I am struggling with, is how then do I save that "layout" - by that I mean the order of the items - how do I save that to state?
When the user re-sorts the times in the UI, I want that layout array to change to reflect the new order.
It seems so simple, but I just haven't seen yet how to do it.
import React, { Component } from 'react'
import Papa from 'papaparse'
import GridLayout from 'react-grid-layout'
import {
Jumbotron,
Container,
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
NavItem,
NavLink,
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
Button,
Input,
} from 'reactstrap'
import '../node_modules/react-grid-layout/css/styles.css'
import '../node_modules/react-resizable/css/styles.css'
import './App.css'
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [], // on load
isOpen: false,
};
this.toggle = this.toggle.bind(this);
this.handleChange = this.handleChange.bind(this);
this.updateData = this.updateData.bind(this)
this.renderData = this.renderData.bind(this)
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
handleChange(event) {
event.preventDefault()
const inventory = event.target.files[0]
Papa.parse(inventory, {
header: true,
complete: this.updateData
})
} // END
updateData(results) {
const data = results.data
this.setState({data}) // {data:data}
}
renderData() {
return this.state.data.map((item,index) => (
<div className="react-grid-item grid-item" key={item.sku} data-grid={{x: index % 3, y: Math.floor(index / 3), w: 1, h: 1}}>
<div> {item.name} </div>
<div> {item.gridorder} </div>
<div> {item.designer} </div>
<img src={item.image} alt="product" />
<div> {item.sku} </div>
<div> {index} </div>
</div>
))
}
// QUESTION: How do I save this layout to state each time it rerenders?
// NOTE: on click of export button, I want to pass that reordered layout held in state to handleClick and parse it back to CSV
// handleClick(event) {
// Papa.unparse({
// })
// }
render() {
return (
<div>
<Navbar color="dark" dark expand="md">
<NavbarBrand href="/">GO App - grid order tool</NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink href="/components/">Components</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/reactstrap/reactstrap">GitHub</NavLink>
</NavItem>
<UncontrolledDropdown nav inNavbar>
<DropdownToggle nav caret>
Options
</DropdownToggle>
<DropdownMenu right>
<DropdownItem>
Option 1
</DropdownItem>
<DropdownItem>
Option 2
</DropdownItem>
<DropdownItem divider />
<DropdownItem>
Reset
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
</Collapse>
</Navbar>
<Jumbotron >
<Container>
<h4> Import CSV </h4>
<Input type="file" onChange={this.handleChange} />
</Container>
</Jumbotron>
<Container className="album ">
<div className="note" > BUG: Drag tiles from text, not image </div>
<div className="note" > BUG: Drag order will be changed </div>
<GridLayout compactType="horizontal" useCSSTransforms={true} cols={3} margin={[120, 20]} rowHeight={300} className="react-grid-layout grid" width={1200} >
{this.renderData()}
</GridLayout>
<Navbar color="light" light expand="md">
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<div className="note" > NOTE: The export function is under construction </div>
<Button onClick={this.handleClick} color="secondary" size="sm">Export CSV</Button>
</NavItem>
</Nav>
</Collapse>
</Navbar>
</Container>
</div> // END
);
}
} // END
export default App
You can move the state one component above and make the grid display of itens a functional component that only receives an array and display the grid.
With that said, to sort the list, on the parent component, you call the
this.setState({data: this.state.data.sort(...)})
and pass this to the child that expects an array to display the grid. So the render method on the parent component should be:
render () {
const { data } = this.state;
return (
<ChildComponent itensList={data} />
);
}

react router takes two click to update the route

I have used react-router v4 for routing in my application. I have used routing to show various form like for showing apartment form, experience form, login, register etc.
Problem
When i click on apartment image, react router routes to apartment form. The route becomes /apartment. If i again then click on register button, the route do not get updated. I have to double click on register button to update the route to /register.
Here is my code
class App extends Component {
constructor(props, context) {
super(props, context);
console.log('context', context);
this.state = { show: false };
}
showModal(e) {
e.preventDefault();
this.setState({ show: true });
}
hideModal() {
this.setState({ show: false });
}
render() {
return (
<div className="container-fluid">
<Nav
showModal={(e) => this.showModal(e)}
hideModal={() => this.hideModal()}
show={this.state.show}
onHide={() => this.hideModal()}
/>
</div>
);
}
}
App.contextTypes = {
router: React.PropTypes.object
};
const Nav = (props) => (
<Router>
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="">
<img
alt="Brand"
className="img-responsive"
src={logo}
role="presentation"
/>
</a>
</div>
<div className="collapse navbar-collapse" id="collapse-1">
<ul className="nav navbar-nav navbar-right nav-social-icon">
<li className="dropdown">
<a
href=""
className="dropdown-toggle"
data-toggle="dropdown"
>
ES
<span className="caret" />
</a>
<ul className="dropdown-menu" style={{ color: '#000', fontWeight: 'bold' }}>
<li onClick={() => props.selectedLocale('en')}>
en
</li>
<li onClick={() => props.selectedLocale('es')}>
es
</li>
</ul>
</li>
<li className="btn-group regLog">
<button
className="btn btn-default"
onClick={props.showModal}
>
<Link to={{ pathname: '/signup' }}>
{props.intl.formatMessage({ id: 'nav.registration.text' }) }
</Link>
</button>
<button
onClick={props.showModal}
className="btn btn-default"
>
<Link to={{ pathname: '/login' }}>
{props.intl.formatMessage({ id: 'nav.login.text' }) }
</Link>
</button>
{props.show ?
<ModalForm
show={props.show}
onHide={props.onHide}
/> : <span />
}
</li>
</ul>
</div>
</div>
</nav>
</div>
</Router>
);
class ModalForm extends Component {
render() {
const { show, onHide, intl } = this.props;
return (
<Router>
<Modal
{...this.props}
show={show}
onHide={onHide}
dialogClassName="custom-modal"
>
<Modal.Header closeButton>
<Link to='/login' className="logTitle">
<Modal.Title id="contained-modal-title-lg">
{intl.formatMessage({ id: 'nav.login.text' })}
</Modal.Title>
</Link>
<Link to='/signup' className="logTitle">
<Modal.Title id="contained-modal-title-lg">
{intl.formatMessage({ id: 'nav.registration.text' })}
</Modal.Title>
</Link>
</Modal.Header>
<Modal.Body>
<Match pattern='/login' component={Login} />
<Match pattern='/signup' component={Signup} />
</Modal.Body>
</Modal>
</Router>
);
}
}
I think its because of using onClick event and routing. How can i solve it?
UPDATE
I tried to use router context but i am getting undefined. App is a parent component and Nav is a child component. Nav component uses router while onClick functions are handled in App component where this.context.router has to be handled.
Thanks
Put the redirect on onClick function using router context ...
https://github.com/ReactTraining/react-router/blob/master/docs/API.md#routercontext
You use contextTypes from react to access router from react-router and the n use push to change url
I am also using RRv4, to handle button links as you have then I wrap the button in the link. The put the overall click handler on the link. This should call prior to the transition and if you need to prevent transition you can simply call e.preventDefault
This will maintain the declarative nature of RRv4 and prevent the need to use the experimental context feature in react.

Categories

Resources