I have run into a situation where it seems I need to pass the children of one component over to another that is a sibling of the original. This doesn't sit well with me as it seems to go against what I've learned is the proper hierarchy and communications channels in React. I need the components to render as siblings due to styling issues, but I'd like to have a logical grouping of components for developers utilising my component.
In short I have some buttons and some of these buttons display a drop-down menu. Like a toolbar of sorts. I want the menu to pop up in a modal like way and so I don't want to place a sub-div next to the button. Instead I want it to render below the buttons and just swap its components with whatever menu is currently active.
Here is how I envision the rendering to look:
<ul>
<li><button>Triggers some action elsewhere</button></li>
<li><button>Button with menu</button></li>
<li>Link</li>
<li><button>Button with menu</button></li>
<li><button>Triggers some action elsewhere</button></li>
</ul>
<div class="menu-container">
Menu content goes here
</div>
Since the buttons are 1-1 linked with a menu I want the developer to work with the components like this:
<Nav>
<NavButton text="Triggers some action elsewhere"/>
<NavMenu text="Button with menu">
<Link to="/">A link</Link>
<Box>
...
</Box>
</NavMenu>
<NavLink>
<Link to="/">Link</Link>
</NavLink>
<NavMenu text="Button with menu">
<Link to="/">A link</Link>
<Box>
...
</Box>
</NavMenu>
<NavButton text="Triggers some action elsewhere"/>
{/*
This component is dynamically inserted by <Nav/> at this position.
It is responsible for rendering a floating menu and controlling its
behaviour.
*/}
<FloatingMenu></FloatingMenu>
</Nav>
The <Nav> component would then swap the content of the .menu-container div based on whether a menu was open or not.
EDIT!
I forgot to mention that there is a separate component here that the developer doesn't see. The <FloatingMenu> component is dynamically inserted by <Nav> and not actually part of the set of children that the developer will write. It is responsible for rendering the actual menu div and controlling its behaviour. So what I'd like to do is move all children from the currently active <NavMenu/> component into the <FloatingMenu/> and empty it out if no menus are active. At least that was my original idea.
/EDIT!
Can this be done? Am I over complicating or misunderstanding something? Any help would be much appreciated!
Related
I'm using Reactstrap to style my React/Redux app, and I'm having some trouble aligning things as I'd like; I know I'm giving up easy access to finer-grained control using the library, but I suspect there's a way to do what I want.
So, I have a basic Navbar at the top of my content (I compressed the Nav options).
<Navbar light expand={ "lg" }>
<NavbarBrand>Redacted Name</NavbarBrand>
<NavbarToggler onClick={ () => this.setState({ isOpen: !this.state.isOpen }) } />
<Collapse navbar isOpen={ this.state.isOpen }>
<Nav navbar>
<UncontrolledDropdown className={ "mr-lg-2" } nav inNavbar>
<DropdownToggle nav>
About Us
</DropdownToggle>
<DropdownMenu>
<DropdownItem>
<Link to={ "/" }>Mission Statement</Link>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
{ userOptions }
</Collapse>
</Navbar>
Now, userOptions is a form that changes based on user input, but all... forms of it take this basic inline form layout, save for differences in buttons and links inside.
<Form className={ "userStatusForm" } inline >
// Content
</Form>
Here's my issue: in the simple layout I'm using, the brand, toggle, nav, and user form pile against each other on the left. However, I'm wanting content inside the Collapse element to use a standard "justify content between" alignment to press the user form against the right side, regardless of its size. That said, I'm struggling to find what I need in the Reactstrap docs - and to phrase what I'm trying to do correctly for Google.
So, I was trying to avoid direct className assignments, since I've already decided to use the Reactstrap library, but the simplest thing involved a mr-auto class added on to the Nav component that forms the first item inside the Collapse container. Not as elegant as I'd hoped, but it's simple (and was good enough for the Navbar in the Reactstrap docs).
I'm learning the basics of React Router. So what I'm making right now has a navigation bar on top and two buttons below this top bar. What I want is for the a table or something of the sort to show up when I press one of the buttons.
The problem is that when I click the button, the URL changes but the all the components vanish. Even the component I want displayed doesn't show and the other components (which ideally should stay) also disappear.
What am I doing wrong here? The code is as follows :-
const Site = () =>
<React.Fragment>
<div className="container-fluid row">
<div className="offset-3 col-sm-4">
<Link to="/A">
<Button value="A"/>
</Link>
</div>
<div className="col-sm-4">
<Link to="/B">
<Button value="B"/>
</Link>
</div>
</div>
<div>
<Route path="/B" component={B}/>
</div>
</React.Fragment>
export default Site;
The Site page has the URL '/Site'.
Edit:
Just thought I'd mention the structure a bit. So for now I have a page with a button. Clicking this button should load the a component (called Base with URL '/Site') which is calling the TopBar and Site components.
Then I have these two buttons - A and B which have their respective URLs.
I am using react and semantic. I am using the multiple sidebar example. The idea is that the left hand sidebar offers up some menu options, and then the right hand sidebar is the sub menu based on which option from the left menu is chosen. When a sub menu item is selected, a component is added to the Sidebar.Pusher, i.e displayed on the page.
It all works except re-rendering the content of the Sidebar.Pusher. This apparently only updates when the left hand side bar's visibility changes. I am using redux/rematch to handle state, and can see that the state that holds the content of the Sidebar.Pusher is being updated, but `render() is only being called when visibility changes of the sidebar.
The content of Sidebar.Pusher is an array, and I even tried displaying on the page the length of the array, which is being updated (pushed into) each time an item on the right hand sidebar is clicked. However this doesn't cause a render() to be fired, its literally when the left hand sidebar visibility changes.
Just to note, I did see this issue, however its from last year, and the answer wasn't enough for me to be able to fix the issue. Help would be appreciated.
Structure:
Index.js renders App.js, App.js renders Menu.js (which is a semantic set of tabs). One of the menu options is Sidebar.js which renders:
<Sidebar.Pushable as={Segment}>
<Sidebar
as={Menu}
animation="overlay"
direction="right"
inverted
vertical
visible={secondaryVisibility}
width="wide"
>
{focusedList.map((el, i) => {
return (
<Menu.Item key={i} as="a" onClick={() => this.addSegment(el)}>
<Article el={el} />
</Menu.Item>
)
})}
</Sidebar>
<Sidebar
as={Menu}
animation="overlay"
icon="labeled"
inverted
// onHide={this.handleSidebarHide}
vertical
visible={primaryVisibility}
width="wide"
>
<Menu.Item
onClick={() => this.changeTab(menuItem)}
as="a"
name="menuItem"
header
>
Menu Item
</Menu.Item>
</Sidebar>
<Sidebar.Pusher style={{ minHeight: "600px" }}>
<Segment basic>
{segments.map((el, i) => {
console.log(`el ${el}`)
return <Content key={i} segment={el} />
})}
</Segment>
</Sidebar.Pusher>
and all state (secondaryVisibility etc) is stored in rematch
Thanks
I haven't been able to identify the problem based on the code you've posted, could you provide more info such as the entire Sidebar.js and maybe what's in the Content component?. My guess would be that there's a HOC or lifecycle method getting in the way.
I've created a trivial example that seems to work fine, if I understand what you're trying to accomplish: https://codesandbox.io/s/myl6xpz9py
I got it. I forgot about immutability in state. Perhaps someone will benefit from this.
I was trying to update a state array with
let tmp = prevState.contract.segments
tmp.push(segment)
this.update({ segments: tmp })
However, this won't work as tmp is a reference to prevState.contract.segments, so this won't work, as pushing to tmp is equivelent to pushing to prevState.contract.segments.
you have to have a completely new array:
const tmp = [...prevState.contract.segments, segment]
this.update({ segments: tmp })
Now it works.
I have a sliding-menu component.
It has items and I want to hide the menu when I click on each item. But if i click on
Now I did so:
<nav onClick={this.handleClickCloseMenu}>
<Link
to="/smth"
activeClassName="is-active"
>
smth
</Link>
<Link
to="/smth2"
activeClassName="is-active"
>
smth2
</Link>
</nav>
Now I have an eslint errors: jsx-a11y/no-noninteractive-element-interactions end jsx-a11y/no-static-element-interactions
I can set role button to nav but i guess it is wrong way. What do you think about?
I thought a little and decided to tie into the key parameter, it's generated by react-router. In componentDidUpdate, look at the key and if the current one differs from the previous one, then hide the menu. If it is open of course. streletss thank you for pushing a thought
I am reading React documentation and I have following two queries about child reconciliation.
Following link says that when children are deleted, instead of deleting them, they can be hidden with display set to 'none'. The specific sentence is:
"In most cases, this can be sidestepped by hiding elements instead of destroying them"
Who is supposed to sidestep? Does React do it automatically or does the programmer have to indicate to React framework to set display style to 'none' instead of reusing it?
(Link: https://facebook.github.io/react/docs/multiple-components.html#stateful-children)
Following link says that in case of reordered children, React can be informed to avoid unnecessary node deletes by assigning a key to each child. However, these keys should be assigned to the component and not to HTML container. But example before that shows assigning key to HTML container which is <li> in that case. What am I missing here?
(Link: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)
This is explicit on the part of the programmer. You should program the component to set a dynamic style to hide the element if you want this behavior, as per the example:
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p style={{display: 'none'}}>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
You should put the key on the top-level element or component returned from the map function. In this example, it's the li:
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
In this example, it's the component that renders the li.
{this.props.results.map(function(result) {
return <ListItemWrapper key={result.id} data={result}/>;
})}