How to create toggleable sidenav layout in React.js? - reactjs

I am porting my layout from jQuery to React.js. This is very common one that consists of:
header with toggle button
sidenav with navigation links
content whose width adapts to sidenav state.
As you can imagine to achieve that a lot of (css) stuff is going on. I am really confused about possible approaches.
Here is mine:
class CoreLayout extends Component {
constructor(props) {
super(props)
this.state = {
sidenavCollapsed: false
}
}
onSidenavToggle() {
const { sidenavCollapsed } = this.state
document.body.classList.toggle('collapsed', !sidenavCollapsed)
this.setState({ sidenavCollapsed: !sidenavCollapsed })
}
render() {
const { sidenavCollapsed } = this.state
return (
<div>
<Header onSidenavToggle={::this.onSidenavToggle}></Header
<Sidenav>
<div className="content">content</div>
</div>
)
}
}
I do all the styling according to class attached to body element:
.collapsed .header {}
.collapsed .sidenav {}
.collapsed .content {}
Basically it's toggling sidenav width and content margin betwen 220 and 60.
So...
Should I pass collapsed property to each of layout elements and add class collapsed separately? What I am trying to achieve is similar to this.
What is the correct way of doing fade-out-in sidenav items animation? Till now I was using jQuery utilities, but I am not sure if directly using window.requestAnimationFrame() is correct. I have tried ReactCSSTransitionGroup with no success.

Just add a class to the navbar on button toggle and animate the transition using css.
See the demo
https://jsfiddle.net/kuLy0g8z/

Related

getting components height before the mounting in React js

I need the way to get known of the my highest component height before rendering the table in ReactJS.
there are a lot of rows and cells, so I created virtualization for my table.
The problem is the following, I cut only visible in the table viewport rows and cells. But my cells have dynamic data from backend. So during scroling they expand and shrink.
Is the way to get the height before mounting? or rendering each cell in hidden component and cached the height?
If you set the style of your row to use a state variable, you can then set this variable on CompomentDidMount. Something like the below.
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = {
minHeight: 0,
};
}
componentDidMount() {
// Or however you get height from a ref
const fooHeight = this.elementFoo.clientHeight;
const barHeight = this.elementBar.clientHeight;
const minHeight = fooHeight > barHeight ? fooHeight : barHeight;
this.setState({ minHeight });
}
render() {
const { minHeight} = this.state;
return (
<div style={{ 'min-height': `${minHeight}px` }} ref={elm => (this.elementFoo = elm)}>Foo</div>
<div style={{ 'min-height': `${minHeight}px` }} ref={elm => (this.elementBar = elm)}>Bar</div>
}
}
If you require a virtualized table I would recommend not reinventing the wheel and going for something like react-virtualized.
As for just getting the rendered dimensions of a component, react-virtualized also has an HOC that you can use called CellMeasurer.

How to modify an existing div element in html by react?

Is it possible to use react to show and hide an existing div element by id?
For example, I want use react to have this <div id="example">this is example</div> show and hide by button click and this element is not created by react.
First you need to understand React's philosophy. I strongly suggest you read the official React tutorial: https://reactjs.org/tutorial/tutorial.html.
In this case you would like to appear and disappear a div, this can be accomplished by changing internal state of a React Component. Then you need to create a function that is bound to the context of the instance of the Component.
For example:
class Example extends Component {
constructor(props) {
super(props);
this.state = {
open: true,
};
}
toggle() {
const { open } = this.state;
this.setState({
open: !open,
});
}
render() {
const { open } = this.state;
return (
<main>
<button onClick={this.toggle.bind(this)}>{open ? 'Hide' : 'Show'}</button>
{open && <div id="example"><h1>this is example</h1></div>}
</main>
);
}
}
Here's a codepen: https://codepen.io/anon/pen/PxWdZK?editors=1010

react toggle menu, styling the button different on click

I am trying to build a mobile hamburger menu in my react application, following the How to build a sliding menu using React and Less tutorial.
It is all working fine but I would like to toggle the style of the button depending on if the menu is visible or not. Because of that I tried to but the menu button inside the Menu class instead of outside of it, but that gave me errors. The errors says that I cannot modify the state from within the render function. So, how could i solve this?
I am used to not use react, and in that case I would simply have created a class "showing-menu" on the body element, then I could change whatever style I want depending on if the menu is visible or not. This approach seems to be not so Reacive though, how can I solve this in React?
You could hold the menu toggle in the state then just append that class to the class list. I can't see your existing code so here is what I mean..
class MyClass extends React.Component {
constructor(props) {
super(props);
this.state = {
toggled: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
toggled: true
});
}
render() {
return (
<div>
<div className={"specialClass " + this.state.toggled ? 'myToggledClass' : ''}>
<button onClick={this.handleClick}>Click me!</button>
</div>
)
}
}
So in the above example, as soon as the state toggled is set to true, the myToggledClass is appended to the div class list.

ReactJS displaying / hiding parallel components

Preface: I'm very new to ReactJS, so my question will reflect my lack of understanding of how things work. Right now I'm using React + Alt.
I have a basic page with a parent component (I'll call it MyContainer) that has multiple parallel panel-esque components (MyPanel) displayed side by side. What I'm now trying to implement is each panel component has an Expand icon that when clicked, will make that panel take up the full width of its parent container (ie. width:100%) and hide all other panels (ie: display:none or visibility:hidden). When the button is clicked again, the initial state of all panels is again shown.
So my question is the proper way to implement this in ReactJS/Alt. So far I have the easy part done, which is listening for the Expand button click and updating the state of whether the panel should be displayed as normal or full-width.
export default class MyPanel extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: false
};
this.handleExpand = this.handleExpand.bind(this);
}
handleExpand() {
this.setState({ expanded: !this.state.expanded });
}
render() {
var expandStyle = {};
if (this.state.expanded) {
expandStyle.width = 'calc(100% - 40px)';
}
return(
<div style={expandStyle}>
<ExpandButton onExpandEvent={this.handleExpand} />
{/* Rest of panel props data rendered here */}
</div>
);
}
}
The part I don't know how to do is have this component tell its sibling components whether they should hide or show itself. Trying to find similar questions here, I think there are two approaches: using props in the parent component to keep track of which panels are hidden or shown, or using Store/Actions to keep track of this, but I'm not sure on the implementation of either.
Again, I'm new to ReactJS, so go easy on me :)
You have your methodology for how to expand/hide slightly off: since your panels are all encompassed within a parent component, that component should decide if an individual panel is normal, expanded, or hidden. You should be using the state of the parent component to accomplish this, rather than the state of each panel component. For example:
var Container = React.createClass({
getInitialState () {
return {
expandedPanel: null,
panels: someArrayOfPanelData
};
},
changeExpandedPanel (panelIndex) {
return () => {
this.setState({
expandedPanel: panelIndex
});
};
},
render () {
let panels = this.state.panels.map((panelData, i) => {
return (
<Panel
key={i}
data={panelData}
expanded={(i == this.state.panelExpanded)}
handleExpansion={this.changeExpandedPanel(i)}
/>
);
});
return (
<div>
{panels}
</div>
);
}
});
var Panel = React.createClass({
propTypes: {
...,
handleExpansion: React.PropTypes.function.isRequired
},
handleExpand () {
this.props.handleExpansion();
},
render () {
...
}
});
What you are doing here is passing the parent's event handler down to the children. Since the function is defined in the parent, it has access to the parent's state/props, etc.

react-router transition animation on initial page load

I would like to apply animations to components when I transition with react-router, and I am able to do this only after the initial load, however I want to see the animation on the initial mount as well (page refresh).
This is what I have tried. Note transitionAppear: true did not do anything:
class App extends Component {
constructor() {
super();
}
render() {
let path = this.context.router.getCurrentPath();
path = path.substring(0, path.split('/', 2).join('/').length);
return (
Transitions({component: 'div', transitionName: 'fade', transitionAppear: true},
handler({key: path})
)
)
}
}
On a re-reading of react docs I realised that transitionAppear triggers its own css class (.appear). Adding this class fixed my problem.

Resources