react toggle menu, styling the button different on click - reactjs

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.

Related

React - state not getting updated after a prop being sent from another component

am having a trouble
i do have a popup in my BrowseModalUpload component and i had given state as
class BrowseModalUpload extends React.Component {
constructor(props) {
super(props)
this.state = {
modalIsOpen: this.props.browseAssetComponent ? this.props.browseAssetComponent : false,
...
}}
So initially there is no popup and when you click on one link , setState modalIsOpen to true and modal opens-thats the normal flow
And when i click in close window ,it setState modalIsOpen to false.
So i just clicked on popup it came and i click on close button it goes ,now i click this popup from different component having prop browseAssetComponent as true ,it didn't open up
code for modal is like this
<Modal transparent isOpen={this.state.modalIsOpen} onAfterOpen={this.afterOpenModal} onRequestClose={this.closeModal} ariaHideApp={false}>
this this.state.modalIsOpen is still false,it not gets updated when i call the same from another component and this popup not coming up.
if you guys need more information let me know.
any help will be way to solve my roadblock
You can use componentDidUpdate lifecycle method where you can set the state based on the props.
class BrowseModalUpload extends React.Component {
constructor(props) {
super(props)
this.state = {
modalIsOpen: this.props.browseAssetComponent ? this.props.browseAssetComponent : false,
...
}
componentDidUpdate(prevProps){
if(this.prevProps.browseAssetComponent != this.props.browseAssetComponent)
this.setState ({
modalIsOpen: this.props.browseAssetComponent ? this.props.browseAssetComponent : false)
}}
}
Don't define your props in state.
Better to pass directly like this
<Modal transparent isOpen={this.props.modalIsOpen} onAfterOpen={this.afterOpenModal} onRequestClose={this.closeModal} ariaHideApp={false}>
and handle from parent component function like this
handleModel=()=>{
this.setState(prev=>({modalIsOpen:!prev.modalIsOpen}));
}
Check this example https://codesandbox.io/s/model-popup-o1z0p. I hope it will help you.
By doing this,
constructor(props) {
this.state = {
foo: props.foo
}
}
you just initialized a state from a prop. React doesn't sync the value of this.state.foo with this.props.foo for you.
If you want to change your state when props are changed, you can do it in getDerivedStateFromProps.
static getDerivedStateFromProps(props, state) {
return { foo: props.foo };
}
However, if you read the document of getDerivedStateFromProps carefully, you'll find React doesn't recommend to use this method in most of the situations. From your code, I don't really understand why this.props.browseAssetComponent would affect this.state.modalIsOpen. If you post the whole code I can give further suggestion.

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

Is it good practice to add an event in props.children, to set state in the parent, to set state in a child component

I want to build a control like this...
<ClickLabelEdit labelText='sandwich'>
<input type='text' value='sandwich' />
<button onclick={this.closeForm} />
</ClickLabelEdit>
ClickLabelEdit would have two states; show a readonly label and show an editable form for that label. Click the label and it displays the edit form. The edit form details would be defined in a property or as children so we could include any type of markup here. Inside the edit form we will need a hook to tell the control to hide the edit form and display the label again.
This ClickLabelEdit would be a reusable component...used in multiple places around my application. The data used in the label and the form could be taken from a redux store. I think the state (or props) that define whether the label or edit form should be displayed doesn't belong in the redux store because that state/prop would have to be duplicated everywhere I use this control which could become messy.
So...
where to put the showEditForm prop/state
where to put the onclick label function that alters the showEditForm prop/state
how to close the edit form and show the label again (this would be triggered from the edit form)
I have got this to work but my main question is it acceptable to use state to trigger events like I have done below, ie
onclick in children props -> sets state in parent component -> updates state in child
ClickLabelEdit.js
class ClickLabelEdit extends Component {
constructor(props) {
super(props)
this.state = { showChildren: this.props.showChildren }
}
componentWillReceiveProps(nextProps) {
if (nextProps.closeForm === true) {
this.setState({ showChildren: false });
}
}
onLabelClick() {
this.setState({ showChildren: true })
}
render() {
return (
<div>
{
this.state.showChildren ?
this.props.children
:
<div onClick={this.onLabelClick.bind(this)}>
{this.props.labelValue}
</div>
}
</div>
)
}
}
export default ClickLabelEdit
usage
class ManualTester extends Component {
constructor(props) {
super(props)
this.state = { value: 'sandwich', closeForm: false }
}
onSave() {
//persist data
this.setState({ closeForm: true })
}
render() {
return (
<div style={{ width: 250 }}>
<ClickTextEdit labelValue={this.state.value} closeForm={this.state.closeForm}>
<input type='text' value={this.state.value} />
<button onClick={this.onSave.bind(this)}>close</button>
</ClickTextEdit>
</div>
)
}
}
export default ManualTester

How to create toggleable sidenav layout in React.js?

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/

Change items in list in React when an item has been clicked

I'm quite new to ReactJS and I have trouble understand how different components can communicate with each other.
I do have a component that will render a list and each list item is a different component. I want to keep the components as small as possible.
Now, each list item can have a property named active and if the property is set to true, an additional class is added.
This is the class that defines a single item in the component.
See this below code for my component defining a single list item:
export default class OfficeRibbonTab extends React.Component {
constructor(props) {
super(props);
this.state = {
active: props.active ? props.active : false
}
// Assign all the correct event handlers.
this.setActive = this.setActive.bind(this);
}
setActive() {
this.setState({active: true});
}
render() {
// When the tab is defined as active, add the "active" class on it.
if (this.state.active)
{ var tabClassName = "active"; }
return <li onClick={this.setActive} className={tabClassName}>{this.props.tabName}</li>;
}
}
So, I have propery active which is passed to this component, which I store in the components state.
When I click the list item, I set to state of the current item to be active.
The problem is that I want all the other list items to become inactive, thus setting the state of active to false.
The code below is an overview of my list:
export default class OfficeRibbon extends React.Component {
constructor(props) {
// Call the 'base' constructor.
super(props);
}
render() {
var tabs = [];
// Loop over all the tab elements and define how the element should be rendered.
for (var i = 0; i < this.props.dataSource.tabs.length; i ++)
{
if (i == 1)
{ tabs.push(<OfficeRibbonTab active={true} key={this.props.dataSource.tabs[i].name} tabName={this.props.dataSource.tabs[i].name}></OfficeRibbonTab>); }
else
{ tabs.push(<OfficeRibbonTab key={this.props.dataSource.tabs[i].name} tabName={this.props.dataSource.tabs[i].name}></OfficeRibbonTab>); }
}
return (<div>
<div className="wrap-top">
<OfficeRibbonTitle title={this.props.title}/>
<ul className="tabs">
{tabs}
</ul>
</div>
</div>);
}
}
It doesn't seem like rocket science, but I want to do it the React way without re-inventing the wheel.
Anyone who can guide me in the right direction?
Kind regards
It looks like OfficeRibbonTab manages its own state, which is fine, but it never informs its parent component of the state change. The most common approach would be to supply a callback function to each child component, so that it can then communicate back to the parent:
For example, OfficeRibbon will now contain a function handleTabSelect that gets passed down as a prop to each OfficeRibbonTab. And in OfficeRibbonTab, when a tab is clicked, you simply invoke the callback, and pass in the selected tab's index or id:
OfficeRibbonTab.jsx
setActive(tabIndex) {
this.props.handleTabSelect(tabIndex);
}
OfficeRibbon.jsx
handleTabSelect(tabIndex) {
this.setState({activeIndex: tabIndex});
}
Now in OfficeRibbon, you update your state to set the activeIndex or activeId, again either by the index or an identifier of your choosing. By setting state in OfficeRibbon, we necessarily force a render() of its children. As a result, we simply match the index of the iterator with the activeIndex of your state, when we iterate in render():
<OfficeRibbonTab active={index === this.state.activeIndex} onClick={this.handleTabSelect} ... />

Resources