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)
Related
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
I have this React code:
export default function Technologies({ technologies }) {
return (
<>
{ Object.keys(technologies).map((key, i) => (
<span>
<span className={styles.post}><h3 className={'bold300'}>{key}</h3></span>
<div className={styles.techList}>
<ul key={i}>
{ Object.keys(technologies[key]).map((key2, idx) => (
<li key={idx}>{key2}
{ technologies[key][key2].map(key3 => (
<span key={key3.name} className={styles.badge}><Image src={key3.name} width={key3.w} height={key3.h} /></span>
)) }
</li>
)) }
</ul>
</div>
</span>
)) }
</>
)
}
Here you can see nested iteration, and everywhere I use i or idx to create unique key for list, but still keep getting warning for this string:
...
<ul key={i}>
...
As I said, I know what this error means, and even know how to fix, but not in this case, I just don't know, where I should put key to prevent this warning. Thanks!
The key should be present on the root element. So, the first key should be on the span and not on the ul.
export default function Technologies({ technologies }) {
return (
<>
{Object.keys(technologies).map((key, i) => (
<span key={i}>
<span className={styles.post}>
<h3 className={"bold300"}>{key}</h3>
</span>
<div className={styles.techList}>
<ul>
{Object.keys(technologies[key]).map((key2, idx) => (
<li key={idx}>
{key2}
{technologies[key][key2].map((key3) => (
<span key={key3.name} className={styles.badge}>
<Image src={key3.name} width={key3.w} height={key3.h} />
</span>
))}
</li>
))}
</ul>
</div>
</span>
))}
</>
);
}
I have got form with input
<form onSubmit={handleSubmit}>
<input type="search"
onChange={handleChange}
onFocus={() => setFocus({name: true})}
onBlur={() => setFocus({name: false})}
value={inputName}
/>
</form>
and the list of elements which is rendered after this input field has focus. This input field is live searcher for elements of this rendered list.
the code to render list:
<div>
{
objects.map((object, index) => {
return (
<ul>
<li key={index}>
{object.name}
</li>
</ul>
)
})
}
</div>
I want to make the action that when I click on the list element, the input field gets this element value.
In the picture below, the input field should be Object 2 after I click on Object 2 element
Due to there are two independent jsx objects, I have no idea how can I do this.
You can try to do this with a function triggered onClick on a <li> that sets the inputName value with the object.name :
<div>
<ul>
{
objects.map((object, index) => {
return (
<li key={index} onClick={() => setInputName(object.name)}>
{object.name}
</li>
)
})
}
</ul>
</div>
And by the way I think your <ul> tag should be outside the map
I think it might be silly question to ask but trust me I am new to React . Actually I am working on app where I have different collapsible menu. For example when I click on menu then dropdown show what I want to achieve when user copy manually link and put in the browser then I want to show specific menu . could someone please help me how to achieve this goal .
code
menus.map((item, index) => (
<UnlockAccess
currentUser={userType || null}
roles={item.roles}
key={index}
>
<div key={index}>
<p
onClick={() => {
this.RouteTo(`/${item.url}`);
this.toggle(item.id);
}}
className={`element ${this.state[item.activeTab]}`}
>
<span
className={
collapse === item.id ? "fa fa-minus" : "fa fa-plus"
}
key={index}
></span>
<p className={this.state[item.activeTab]}>
{item.name}
</p>
</p>
{collapse === item.id ? (
<div className="prop-child">
<ul>
{item.children.map((item, index) => (
<li
key={index}
className={this.state[item.activeTab]}
onClick={() =>
this.setState({ collapse: item.itemId }, () =>
this.toggle(item.itemId)
)
}
>
<Link
onClick={() => this.RouteTo(`/${item.url}`)}
to={item.url}
className={this.state[item.activeTab]}
>
{item.name}
</Link>
</li>
))}
</ul>
</div>
) : null}
toggle = (id) => {
if (!this.state.collapse || id !== this.state.collapse) {
this.setState({
collapse: id,
});
}
};
Just check the url params in the componentDidMount of your class. Then open the menu you want to be opened.
When I clicked a link it renders a view based on the "id" from a JSON. I need to apply a background color when a certain view renders. And I should toggle the Style.
This code shows the crawl when I clicked a particular link.
handleCrawl = e => {
const { id } = e.target;
this.setState(current => ({
showCrawl: { [id]: !current.showCrawl[id] }
}));
};
This is my render method where Ia am mapping the links and the additional details on JSON
render() {
return (
<div class="d-flex" id="wrapper">
<div class="bg-light border-right" id="sidebar-wrapper">
<h1 class="sidebar-heading">API</h1>
<ul class="list-group list-group-flush">
{this.state.apis.map(api => (
<li><a class="list-group-item list-group-item-action bg-light" key={api.id}
id={api.id}
onClick={this.handleCrawl}>{api.title}</a></li>
))}
</ul>
</div>
<div id="page-content-wrapper">
<div class="container-fluid">
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}>
{this.state.showCrawl[api.id] && (
<SwaggerUI url={api.opening_crawl}/>
)}
</div>
))}
</div>
</div>
</div>
);
}
Not sure if it answers your question.
You can toggle the style conditionally.
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}
className={this.state.showCrawl[api.id]?"some-specific-style":"default-or-empty"}
>
{this.state.showCrawl[api.id] && (
<SwaggerUI url={api.opening_crawl}/>
)}
</div>
))}