show and hide react JS - javascript

In my react JS Code i have 2 Onclick function
class Traders extends Component {
constructor(props) {
super(props);
this.state = {
value: 10,
listVisibleList: false,
gridVisibleList: false,
listVisibleGrid: false,
gridVisibleGrid: false
};
}
componentDidMount() {
}
onClickListView() {
this.setState({
listVisibleList: !this.state.listVisibleList,
gridVisibleList: !this.state.gridVisibleList
});
}
onClickGridView(){
this.setState({
listVisibleGrid: !this.state.listVisibleGrid,
gridVisibleGrid: !this.state.gridVisibleGrid
});
}
render() {
const widthRisk = {
width: '60%'
};
return (
<div id="home">
<Col xs={12} sm={12} md={2}>
<div className="option-layout">
<ul>
<li>
<a href="#" onClick={() => this.onClickListView()}>
<img src="../../src/assets/images/list.png" className="img-respnsive" alt="list" />
</a>
</li>
<li>
<a href="#" onClick={() => this.onClickGridView()} >
<img src="../../src/assets/images/grid.png" className="img-respnsive" alt="grid" />
</a>
</li>
</ul>
</div>
</Col>
{
this.state.listVisibleList ? <ListTrader /> : <ListTrader />
}
{/* <ListTrader /> */}
{/* <GridTrader /> */}
</div>
)
}
The problem is how i want to show some specific component.
When i click onClickListView it shows <ListTrader /> Component and <GridTrader /> Component hide
When i click onClickGridView it shows <GridTrader /> Component and <ListTrader /> Component hide
I already tried to do some show and hide referring from this question
Show/Hide components in ReactJS
But the onClick from that question the function showing like toggle function. Any idea how to solve this?
Your help really appreciate. Thanks.

This is not working example but hope will give you a direction, (if I correctly understand your issue)You can hold in state string variable and based on value it has display what you want.
class Traders extends Component {
constructor(props) {
super(props);
this.state = {
....
visibleView:'list' //'grid'
};
}
componentDidMount() {}
onToggleView(view) {
this.setState({
visibleView:view
});
}
render() {
const widthRisk = {
width: '60%'
};
return (
<div id="home">
<div className="app-body" id="view">
<div className="padding font-responsive">
<Row>
..............
...............
<Col xs={12} sm={12} md={2}>
<div className="option-layout">
<ul>
<li>
<a href="#" onClick={() => this.onToggleView('list')}>
<img src="../../src/assets/images/list.png" className="img-respnsive" alt="list" />
</a>
</li>
<li>
<a href="#" onClick={() => this.onToggleView('grid')} >
<img src="../../src/assets/images/grid.png" className="img-respnsive" alt="grid" />
</a>
</li>
</ul>
</div>
</Col>
</div>
</Col>
</Row>
{
this.state.visibleView ==='list'? <ListTrader /> : <GridTrader />
}
{/* <ListTrader /> */}
{/* <GridTrader /> */}
</div>
</div>
</div>

Related

How to add className to component based on state without removing initial className

I have a component that is toggleable:
class HamburgerMenu extends React.Component {
constructor(props){
super(props)
this.state = {
toggle: false,
}
}
Toggle() {
this.setState((currentState) => ({
toggle: !currentState.toggle
}));
}
render() {
return (
<StyledHamburgerMenu className="HamburgerMenu" onClick={ () => this.Toggle() }>
<FontAwesomeIcon icon="bars" />
</StyledHamburgerMenu>
)
}
}
and I want to add a class name to a div (extended-right-bar) jsx element in a separate file:
function App() {
return (
<div className="App">
<div className="grid-display">
<div className="right-bar">
<HamburgerMenu />
<PlusButton />
</div>
<div className="extended-right-bar">
<h1 className="main-title">Notes</h1>
<div className="folders-section">
<h2>Folders</h2>
<Folder name="folder" />
<Folder name="folder" />
<Folder name="folder" />
<Folder name="folder" />
</div>
<div className="tags-section">
<h2>Tags</h2>
<Label name="buisness" />
<Label name="buisness" />
<Label name="buisness" />
</div>
</div>
<div className="main">
<NoteWindow />
</div>
</div>
</div>
);
}
How can I do that? They're imported and exported to each other
You can use
element.classList.add("className");
to add a class without overwriting the existing ones.
Replace element and className accordingly
You can use redux to pass classValue on toggle to the different component.
const Component = (props) => {
const className = props.classValue ? "extended-right-bar " + props.classValue : "extended-right-bar";
return (
<div className={customProps.className}>
<h1 className="main-title">Notes</h1>
<div className="folders-section">
<h2>Folders</h2>
<Folder name="folder" />
<Folder name="folder" />
<Folder name="folder" />
<Folder name="folder" />
</div>
</div>;
);
}

Prevent nested <Link/> component from inheriting path from previous <Link/> (React router 4)

I have a Dasboard component where I have React-router
<Link/> components that are linking to
http:<procjethos>/team
Inside <Team/> component I have a <Link/> components that should link to
http:<projecthost>/list/:listId
But instead, it inherits from previous link and I get
http<projecthost>/team/list/:listId
// Dashboard.jsx
render() {
const { shoppingLists, teams } = this.props;
return (
<Fragment>
<Toolbar isHomePage/>
<div className="wrapper">
<div className="dashboard">
<h2 className="dashboard__heading">
<TeamIcon />
Cohorts
</h2>
<ul className="dashboard__list">
{_map(teams, team => (
<li className="dashboard__list-item" key={team._id}>
<Link to={`team/${team._id}`}>
<CardItem name={team.name} />
</Link>
</li>
))}
</ul>
</div>
</div>
</Fragment>
);
// Team.jsx
<Fragment>
<Toolbar />
<div>
Cohort of id:
{id}
<ul>
{_map(lists, list => (
<li className="dashboard__list-item" key={list._id}>
<Link to={`list/${list._id}`} replace>
<CardItem name={list.name} />
</Link>
</li>
))}
</ul>
</div>
</Fragment>
How to achieve the desired behavior in React-Router 4 with nested LINKs?
Add a / before link path
<Link to={`/list/${list._id}`} replace>
<CardItem name={list.name} />
</Link>

React seeing all but on array

I have a child component that sees all the props but one array that I am trying to map over.
react dev tool sees the array:
but I get "Cannot read property 'map' of undefined"
class Header extends Component {
render() {
const nav = this.props.data.nav.map(i => `<li>${i}</li>`)
return (
<div className="header">
<div className="left">
<h1>{this.props.data.name}</h1>
<p>{this.props.data.tag}</p>
</div>
<div className="right">
<h2>{this.props.data.t1}</h2>
<h3>{this.props.data.t2}</h3>
</div>
<div className="header-contact">
<a rel="noopener" href="tel:+14156943568">
<FontAwesomeIcon icon={faPhone} /> {this.props.data.phone}
</a>
<a rel="noopener" href="mailto:tim.smith.hdg#gmail.com">
<FontAwesomeIcon icon="at" /> {this.props.data.email}
</a>
</div>
<nav id="nav" className='nav'>
<ul>
{
//nav
}
</ul>
</nav>
</div>
);
}
}
I'm using the <Header /> component in the follow way:
class Resume extends Component {
constructor(props) {
super();
this.state = { header: {}, skills: {} }
}
componentDidMount() {
this.setState({
...data
});
}
render() {
return (
<div className="resume">
<Header data={this.state.header} />
<Skills data={this.state.skills} />
</div>
);
}
}
You should check that props.data is defined, and that props.data.nav is an array, to address the errors.
The reason you need to perform this check is because the props.data.nav is not present during the first render() of the <Header /> component. This is because the nav data is only available after the componentDidMount() hook in <Resume /> is called (which happens after the first render of <Header />)
You could make the following adjustment to resolve this:
class Header extends Component {
// [UPDATE] add helper method to simplify safer access to data.nav array
getNavItems() {
// If no data, return empty array
if(!this.props.data) return [];
// If nav not an array, return empty array
if(!Array.isArray(this.props.data.nav)) revturn [];
// Safely access/return nav array
return this.props.data.nav;
}
render() {
// [UPDATE] use local helper getNavItems method to safely access item array
const nav = this.getNavItems().map(i => `<li>${i}</li>`)
return (
<div className="header">
<div className="left">
<h1>{this.props.data.name}</h1>
<p>{this.props.data.tag}</p>
</div>
<div className="right">
<h2>{this.props.data.t1}</h2>
<h3>{this.props.data.t2}</h3>
</div>
<div className="header-contact">
<a rel="noopener" href="tel:+14156943568">
<FontAwesomeIcon icon={faPhone} /> {this.props.data.phone}
</a>
<a rel="noopener" href="mailto:tim.smith.hdg#gmail.com">
<FontAwesomeIcon icon="at" /> {this.props.data.email}
</a>
</div>
<nav id="nav" className='nav'>
<ul>
{
//nav
}
</ul>
</nav>
</div>
);
}
}
Can you show from where this.props.data.nav comes from? Maybe when the component mounts, this.props.data or this.props.data.nav is undefined. React dev tool shows the array because after the error, this.props.data.nav is already set and not undefined. Try something like:
var nav = null;
if(this.props.data != undefined && this.props.data.nav != undefined){
nav = this.props.data.nav.map(i => "<li>${i}</li>")
}
You get map is undefined cause you don't get an array. You can't map undefined. The way I will do this will be to get an empty array if I don't have the props yet. This way you can still map over it but receive no element
class Header extends Component {
render() {
const navData = this.props.data && this.props.data.nav || []
const nav = navData.map(i => `<li>${i}</li>`)
return (
<div className="header">
<div className="left">
<h1>{this.props.data.name}</h1>
<p>{this.props.data.tag}</p>
</div>
<div className="right">
<h2>{this.props.data.t1}</h2>
<h3>{this.props.data.t2}</h3>
</div>
<div className="header-contact">
<a rel="noopener" href="tel:+14156943568"><FontAwesomeIcon icon={faPhone} /> {this.props.data.phone}</a>
<a rel="noopener" href="mailto:tim.smith.hdg#gmail.com"><FontAwesomeIcon icon="at" /> {this.props.data.email}</a>
</div>
<nav id="nav" className='nav'>
<ul>
{
//nav
}
</ul>
</nav>
</div>
);
}
}
Or you can handle this case from the parent also
class Parent extends Component {
render() {
return (
<div>
<Header data={this.state.header} nav={this.state.header && this.state.header.nav || []} />
</div>
)
}
}
class Header extends Component {
render() {
const nav = this.props.nav.map(i => `<li>${i}</li>`)
return (
<div className="header">
<div className="left">
<h1>{this.props.data.name}</h1>
<p>{this.props.data.tag}</p>
</div>
<div className="right">
<h2>{this.props.data.t1}</h2>
<h3>{this.props.data.t2}</h3>
</div>
<div className="header-contact">
<a rel="noopener" href="tel:+14156943568"><FontAwesomeIcon icon={faPhone} /> {this.props.data.phone}</a>
<a rel="noopener" href="mailto:tim.smith.hdg#gmail.com"><FontAwesomeIcon icon="at" /> {this.props.data.email}</a>
</div>
<nav id="nav" className='nav'>
<ul>
{
//nav
}
</ul>
</nav>
</div>
);
}
}

Passing props.children to a conditionally rendered component

I have Product component that renders a modal component based on a showModal boolean value in the Product component state. This is the render method in Product
render() {
const { .... } = this.props.data;
return (
<>
{this.state.showModal && (
<Modal
product={this.props.data}
toggleModal={this.onToggleModal}
addToCart={this.props.onAddToCart}
/>
)}
<li className="product-body">
<img
src=".."
onClick={this.onToggleModal}
/>
<h2>{...}</h2>
<h3>{..}</h3>
<h3>{..}</h3>
<h2 className="product-price">{...}</h2>
<button type="button" onClick={this.props.onAddToCart}>
Buy now
</button>
</li>
</>
);
}
I want to pass down the content inside li to the Modal.How can I make use of props.children in this case for the Modal component, so I dont have to pass down the data to be displayed as props ?
If Modal is another component then you can pass the list as
render() {
const { .... } = this.props.data;
return (
<>
{this.state.showModal && (
<Modal
product={this.props.data}
toggleModal={this.onToggleModal}
addToCart={this.props.onAddToCart}
>
<ListItems {...this.props}/>
</Modal>
)}
<ListItems {...this.props}/>
</>
);
}
Let the ListItems be a separate component as
class ListItems extends React.Component {
render() {
return(
<li className="product-body">
<img
src=".."
onClick={this.onToggleModal}
/>
<h2>{...}</h2>
<h3>{..}</h3>
<h3>{..}</h3>
<h2 className="product-price">{...}</h2>
<button type="button" onClick={this.props.onAddToCart}>
Buy now
</button>
</li>
)}
}
class ListItems extends React.Component {
render(){
return(
<li className="product-body">
<img
src=".."
onClick={this.onToggleModal}
/>
<h2>{...}</h2>
<h3>{..}</h3>
<h3>{..}</h3>
<h2 className="product-price">{...}</h2>
<button type="button" onClick={this.props.onAddToCart}>
Buy now
</button>
</li>
)
}
}
class Wrapper extends React.Component {
render(){
return (
<Modal
product={this.props.data}
toggleModal={this.onToggleModal}
addToCart={this.props.onAddToCart}
>
<ListItems />
</Modal>
)
}
}
class Modal extends React.Component {
render(){
return (
<div>
<h1>Modal Title</h1>
<div>{this.props.children}</div>
</div>
)
}
}

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