How to change .jsx component style from inside the .js file? React - javascript

function Navbar() {
const [shownavcontents, setShownavcontents] = useState(false)
if(shownavcontents){
document.getElementsByClassName("navbardivofmobiledevice").style.display = "none";
}else{
document.getElementsByClassName("navbardivofmobiledevice").style.display = "block";
}
return (
<>
<div className="top">
<Searchbar />
<AiOutlineMenu size={20} className="outlinemenu" onClick={() => {setShownavcontents(true)}} />
</div>
<div className="navbardivofmobiledevice">
<ul>
<li>
Home
</li>
<li>
Members
</li>
<li>
All Posts
</li>
<li>
My Posts
</li>
</ul>
</div>
</>
);
}
As you see I am trying to make responsive navbar, in this case, for mobile devices. I've faced one problem. I've made button on top of navbar and some navbar contents which I want to display only whenever user will click this button and vice versa. So I tried using hooks to check if the user clicked the button which works perfectly, only thing that doesn't works is this if else statements it seems like document.getElementsByClassName("navbardivofmobiledevice").style.display = "none"; doesn't have an effect here. So my question is what is the alternative of this? What can I do here?

This is imperative code:
document.getElementsByClassName("navbardivofmobiledevice").style.display = "none";
With React, you rarely get references to DOM elements and update them manually, and in any case, you do it using Refs, not with the getElement... or querySelector... methods). Instead, you write declarative code and let React take care of the DOM updates for you.
In this case, simply add or remove a hidden attribute or CSS class that has display: none from your JSX:
function Navbar() {
const [shownavcontents, setShownavcontents] = useState(false);
return (
<>
<div className="top">
<Searchbar />
<AiOutlineMenu size={20} className="outlinemenu" onClick={() => {setShownavcontents(true)}} />
</div>
<div className="navbardivofmobiledevice" hidden={ !shownavcontents }>
<ul>
<li>
Home
</li>
<li>
Members
</li>
<li>
All Posts
</li>
<li>
My Posts
</li>
</ul>
</div>
</>
);
}
If you prefer to use a class, assuming you have defined a CSS class .isHidden { display: none; } you would use this line instead:
<div className={ `navbardivofmobiledevice${ shownavcontents ? '' : ' isHidden' }` }>
Regarding what some comments are mentioning about rendering that conditionally like so:
function Navbar() {
const [shownavcontents, setShownavcontents] = useState(false);
return (
<>
<div className="top">
<Searchbar />
<AiOutlineMenu size={20} className="outlinemenu" onClick={() => {setShownavcontents(true)}} />
</div>
{ shownavcontents && (
<div className="navbardivofmobiledevice">
<ul>
<li>
Home
</li>
<li>
Members
</li>
<li>
All Posts
</li>
<li>
My Posts
</li>
</ul>
</div>
) }
</>
);
}
I would avoid that, as hiding your main navigation from Google and other search engines will harm your SEO. You need to hide it visually but still have it in the DOM.
If you want to do better than that, add all the appropriate ARIA attributes and logic for a navigation menu with nested submenus, as explained here:
https://www.w3.org/WAI/ARIA/apg/example-index/menubar/menubar-navigation

Related

Debugging - Self closing tag?

I've spent quite some time trying to find where the missing closing tag is and I'm losing my mind or have gone cross-eyed. All throughout the component I'm getting bugs that say 'Expression Expected' or 'Declaration or statement expected'
I know that I need to close the tags with a '/>/ at the end but I can't find where exactly could be causing the problem.
import { useState } from "react";
import logo from "../icons/logo.svg";
import CSS from "../styles/Navigation.css";
import hamburger from "../icons/icon-hamburger.svg";
import { MobileMenu} from "../components/MobileMenu"
function navigation() {
return (
<div className="navigation">
<img className="logo" src={logo} alt="coffee-roasters-logo" />
<button className="hamburger">
<img src={hamburger} />
</button>
<div className="navigation-menu">
<ul>
<li>
Home
</li>
<li>
About Us
</li>
<li>
Create Your Plan
</li>
</ul>
</>
</div>
)
}
export default navigation;
second last tag change </> to </div> to close one of the earlier divs
function navigation() {
return (
<div className="navigation">
<img className="logo" src={logo} alt="coffee-roasters-logo" />
<button className="hamburger">
<img src={hamburger} />
</button>
<div className="navigation-menu">
<ul>
<li>
Home
</li>
<li>
About Us
</li>
<li>
Create Your Plan
</li>
</ul>
</div>
</div>
);
}

Submenu is not working for multiple items in ReactJs?

I have submenu that is working for only when there is single item single LI but if I increase LI then its not working fine. How can I solve this?
My Code:-
import React, { useState } from "react";
import { Link } from "react-router-dom";
const Home = (props) => {
const [subMenuOpen, setSubMenuOpen] = useState(false);
return (
<>
<ul className="submenu">
<li>
<Link to="/">
<div
onClick={() => setSubMenuOpen(!subMenuOpen)}
>
<span>test</span>
</div>
</Link>
<ul class={`sub-menu ${subMenuOpen ? "is-open" : ""}`}>
<li className="menu-item">Sub-Item 1</li>
<li className="menu-item">Sub-Item 2</li>
<li className="menu-item">Sub-Item 3</li>
</ul>
</li>
<li>
<Link to="/">
<div
onClick={() => setSubMenuOpen(!subMenuOpen)}
>
<span>test</span>
</div>
</Link>
<ul class={`sub-menu ${subMenuOpen ? "is-open" : ""}`}>
<li className="menu-item">Sub-Item 1</li>
<li className="menu-item">Sub-Item 2</li>
<li className="menu-item">Sub-Item 3</li>
</ul>
</li>
</ul>
</>
);
};
export default Home;
.sub-menu { display: none;}
.sub-menu.is-open { display:block;}
ThankYou!
Because you have multiple submenus, you need to keep track of which one is open, and you can't do that with a single bool value.
If you will have only 1 level of child menu items, and at most one of them can be open, you can use a number: -1 -> no subitem is open, 0 -> the first item is open, etc. like this:
const [subMenuOpen, setSubMenuOpen] = useState(-1);
1st div: <div onClick={() => setSubMenuOpen(0)}>
2nd div: <div onClick={() => setSubMenuOpen(1)}>
(etc)
1st ul: <ul class={`sub-menu ${subMenuOpen === 0 ? "is-open" : ""}`}>
2nd ul: <ul class={`sub-menu ${subMenuOpen === 1 ? "is-open" : ""}`}>
(etc)
you probably also need to provision something that clears the menu, so clicking outside of the menu would run setSubMenuOpen(-1).
To get toggling behaviour, you can use a helper function like this:
helper function: const toggleMenu = (x) => setSubMenuOpen(subMenuOpen === x ? -1 : x)
1st div: <div onClick={() => toggleMenu(0)}>
2nd div: <div onClick={() => toggleMenu(1)}>
If you plan to have multiple levels of menu items, then a tree-like data structure will be more suitable, perhaps to both define the menu and to keep track of the open (sub)(sub)(sub)item.
try using "className" instead of "class"
JSX seems to be right
I think you have a problem in css

React JS render list data in separate row

I am facing an issue in React Js. I want to show names data in each separate row.
const names = ['James', 'John', 'Paul', 'Ringo'[![\]][1]][1];
My Code:
return (
<div class="col-lg-8 bar-name">
<div>
{names.map(filteredName => (
<li>
{filteredName}
</li>
))}
</div>
</div>)
How can i use in div element ? What should i do?
can anyone help me?
You need to add elements to want to be displayed alongside in the List tag.
Example:
return (
<div class="col-lg-8 bar-name">
<div>
{names.map(filteredName => (
<li>
{filteredName}
<div>
Ryan
</div>
<div>
Eric
</div>
</li>
))}
</div>
)

React js - pass value to child to parent to another child

I am trying to pass the data from Child > parent > child
Child
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
<li key={i} onClick={this.props.toggleContent}>
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
Basically I need to get selected country and some other values from the child and pass to parent
and pass those values to another child.
My Parent
<div className="modal-header">
<h2>Choose your {title}</h2>
<a href="#" className="model-close" data-dismiss="modal" aria-label="Close"><i
className="fa fa-times-circle"></i></a>
</div>
<div className="modal-body">
{showCountry && <CountryList toggleContent={this.toggleContent}/>}
{showLanguages && <RegionList country={country} flag={flag} languages={languages}
toggleContent={this.toggleContentRegion.bind(this)}/>}
</div>
and
toggleContent = () => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: 'country',
languages: [],
flag: 'flag'
});
}
I tried to use below
<li key={i} onClick={this.props.toggleContent(c.country)}>
<img src={c.flag}/> {c.country}
</li>
and access it from parent
toggleContent = (country) => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: country,
languages: [],
flag: 'flag'
});
}
But, my components not working correctly When do that and always shows the 2 child component.
Are there any proper way to pass the data to parent from a json array?
So the best way I would handle this would be to make the import your parent class components into the child , place it at the very top of the child JSX but hide it by default. The modal would be fixed, background covering the full page and at a z-index higher than the rest of the child components, so that way only the modal contents are the only accessible things . You would have a state that "toggles on" the modal for each click of the item list and a close button that toggles it off. You would update the modal content and toggle it on for every click
In terms of the second child, you can just show it on the same modal
Found a way to do this :)
render() {
var toggleContent = this.props.toggleContent;
return (
<div className="modal-wrapper">
<ul className="country-list">
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
**<li key={i} onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)} >**
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
Changed below line
onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)

React switching between lists with same class

I have main component which has 4 subcomponents and I wish to pass states props and functions between them. The thing is that in subcomponent List I wish to be able to get access only to interior of the list with the class ".title" Is it any way to jump between same classes in react as it was possible in jQuery? something like this next(), prev() and find()? I tried to find any way but I have failed so far.
class List extends React.Component {
constructor(props) {
super(props)
this.state = {
title: ""
}
}
render() {
return (
<div>
<ul className="List">
<li>
<ul className="song">
<li className="time">
3:16
</li>
<li className="title" onClick= {this.handleSong}> Title I want to pass
</li>
</ul>
</li>
<ul className="List">
<li>
<ul className="song">
<li className="time">
4:16
</li>
<li className="title" onClick= {this.handleSong}> next Title I want to pass
</li>
</ul>
</li>
</div>
and here is function where I can get access to one element but don't know how to switch to next one
handleSong = (event) => {
this.setState({
title: event.currentTarget.textContent,
})
event.preventDefault()
}
UPDATED:
I changed my code as you suggested and now it looks like this:
Inside main component:
class Widget extends React.Component {
constructor(props) {
super(props)
this.state = {
isClicked: true,
playerDisplayed: true,
title: "Still Don't Know",
songs: []
}
}
componentDidMount() {
const url = "http://localhost:3000/ListOfSongs"
fetch(url)
.then(resp => resp.json())
.then(data => {
this.setState({
songs: data
})
console.log(data);
});
}
return (
<div className="container">
<div className="wrapperList">
<HeaderList
handleReturn={this.handleReturn.bind(this)}/>
<ul className="songsList">
{this.state.songs.map(e =>
<SongsList id={e.id} title={e.title} time={e.time}
handleChooseSong={this.handleChooseSong.bind(this)}
playerDisplayed={this.state.playerDisplayed}/>
)}
</ul>
</div>
</div>
)
}
SongList component :
<li id={this.props.id}>
<ul className="song">
<li className="timeAndBand">
{this.props.time} || {this.props.band}
</li>
<li className="title" onClick={this.props.handleChooseSong}>
{this.props.title}
</li>
<li className="icons">
<svg aria-hidden="true" data-prefix="fas" data-icon="share-alt"className="shareBtn" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
</svg>
<svg aria-hidden="true" data-prefix="fas" data-icon="heart"
className="heartBtn" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
</svg>
</li>
</ul>
</li>
Each song should be a component:
<Song id={song.id} title={song.title} time={song.time}
handleClick={someHandlerInParent} />
in <Song /> of course html and
onClick={ this.props.handleClick( this.props.id ) }
This way you can pass to List component (parent) information about which song was selected, filter by id, get title, time, whatever. Render list using map, you can tell Song (by prop) that is currently selected to render with another style/class ... NOT BY getting/selecting DOM node and adding/removing classes - it's a lot simpler and more powerfull with react - render fn can have logic to choose style, show additional options (components).
Search for more tutorials, even TODO examples - react is not another templating engine - you have to learn thinking in react. It's hard to just start writting code w/o some knowledge.
UPDATE: Look at this example - component can contain much more (complex) data w/o need to 'artificially pumping it into html' (each template engines needs it). You can show in html only part of data and still use all 'behind scene'! No more searching for id (next/prev/n-th child...), get value, prop, state ... or manually roll-back changes (grrr#$%). You can manipulate objects w/o hand tools, not step by step (error prone) - with react you have automation 'CNC' for this.

Categories

Resources