How to set state in React and Material-ui over .js files? - reactjs

I'm new for React and Material-UI too. I have this App.js file:
import React, {Component} from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import NavigationMenu from 'material-ui/svg-icons/navigation/menu';
import DrawerMenu from './DrawerMenu';
const AppBarIcon = () => (
<AppBar
title="Title"
iconElementLeft={<IconButton onClick={???}>
<NavigationMenu />
</IconButton>}
/>
);
class App extends Component {
render() {
return (
<div className="App">
<MuiThemeProvider>
<div>
<DrawerMenu />
<AppBarIcon />
</div>
</MuiThemeProvider>
</div>
);
}
}
export default App;
...and this is the DrawerMenu.js file:
import React from 'react';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
export default class DrawerSimpleExample extends React.Component {
constructor(props) {
super(props);
this.state = {open: false};
}
handleToggle = () => this.setState({open: !this.state.open});
render() {
return (
<div>
<Drawer open={this.state.open}>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
</div>
);
}
}
Is there any way to set the IconButton's onClick value in App.js file to set the DrawerMenu's state open:true ? For example:
<IconButton onClick={ DrawerMenu.setState({open:true}) }>
...or something like this?

You can use props to achieve desired behavior.
Example
const AppBarIcon = (props) => (
<AppBar
title="Title"
iconElementLeft={<IconButton onClick={props.onIconClick}>
<NavigationMenu />
</IconButton>}
/>
);
class App extends Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
}
onIconClick = () => {
this.setState((prevState) => ({ isOpen: !prevState.isOpen }));
}
render() {
return (
<div className="App">
<MuiThemeProvider>
<div>
<DrawerMenu isOpen={this.state.isOpen} />
<AppBarIcon onIconClick={this.onIconClick} />
</div>
</MuiThemeProvider>
</div>
);
}
}
export default class DrawerSimpleExample extends React.Component {
constructor(props) {
super(props);
this.state = {open: false};
}
handleToggle = () => this.setState({open: !this.state.open});
render() {
return (
<div>
<Drawer open={this.props.isOpen}>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
</div>
);
}
}

Related

react-modal won't close after onClick event from another component

first time exploring Gatsby and tried to install react-modal. Added modal component inside my ComponentOne and inside the modal is another component which is ComponentTwo where the close trigger resides. Already passed the onClick to ComponentTwo but still no luck. I think I miss something.
ComponentOne
import React, { Component } from "react"
import ComponentTwo from "./ComponentTwo"
import Modal from 'react-modal'
export default class ComponentOne extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false
};
this.handleOpenModal = this.handleOpenModal.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleOpenModal() {
this.setState({ showModal: true });
}
handleCloseModal() {
this.setState({ showModal: false });
}
render() {
return (
<div className="container mx-auto h-50">
<Modal
isOpen={this.state.showModal}
ariaHideApp={false}
style={cotentStyle}
>
<ComponentTwo onClick={this.handleCloseModal} /> // this is component two
</Modal>
</div>
)
}
}
ComponentTwo
import React from 'react'
import { TiDelete } from 'react-icons/ti'
const NavContent = ({ data }, props) => (
<>
<div className="bg-black z-10 absolute inset-0">
<button onClick={props.onClick} className="text-white absolute top-0 right-0 my-4 mx-4">
<TiDelete size={'2em'} />
</button>
</div>
</>
)
export default function Nav(props) {
return (
<StaticQuery
query={worksQuery}
render={data => <NavContent data={data} {...props} />}
/>
)
}
Try with:
export default function Nav({onClick}) {
return (
<StaticQuery
onClick={onClick}
query={worksQuery}
render={data => <NavContent data={data} {...props} />}
/>
)
}

Toogle button not updating state properly

I have a button that I am using to toggle my sidebar in react application. The toggle button works fine for first two toggle states than it repeats the state twice for third time.
This is how I am toggling state from child component to parent:
import React, { Component } from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
toggle: false
}
}
toggleSidebar = () => {
this.setState({
toggle : !this.state.toggle
});
console.log(this.state.toggle)
this.props.getToggleState(this.state.toggle);
}
render() {
return (
<div>
<button style={{width: '60px'}} onClick={this.toggleSidebar}>Toogle</button>
</div>
)
}
}
export default class App extends Component{
constructor(props) {
super(props)
this.state = {
toggleVal:''
}
}
getData = (val) => {
this.setState({
toggleVal: val
})
}
render(){
let toggleConst = '';
if(this.state.toggleVal){
toggleConst = (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
<Routes/>
<Footer/>
</div>
</div>
</Router>
)
}
else{
toggleConst = (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<SideNav toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
<Routes/>
<Footer/>
</div>
</div>
</Router>
)
}
return (
toggleConst
);
}
}
Toggling the button hides/open the sidebar perfectly but it stuck on state when gets 'false' as twice.
This is how state console goes:
I am not able to find the problem here. Any help appreciated.
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'
export default class App extends Component{
constructor(props) {
super(props)
this.state = {
toggleVal: false
}
}
getData = (val) => {
this.setState({
toggleVal: val
});
}
render(){
console.log("called.....123...",this.state.toggleVal)
if(this.state.toggleVal){
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<Sidebar toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData} />
</div>
</div>
</Router>
)
}
else{
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<Sidebar toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
</div>
</div>
</Router>
)
}
}
}
Header.js
import React, { Component } from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
toggle: false
}
}
toggleSidebar = () => {
this.setState({
toggle: !this.state.toggle
},()=>{
// console.log(this.state.toggle)
this.props.getToggleState(this.state.toggle);
});
}
render() {
return (
<div>
<button onClick={()=>this.toggleSidebar(this.state.toggle)}>Toogle</button>
</div>
)
}
}
Sidebar.js
import React, { Component } from 'react'
import { NavLink } from "react-router-dom";
export default class Sidebar extends Component {
render() {
return (
<>
{
this.props.toggleVal &&
<div className="sidebar_container">
<nav className="nav_container">
<ul>
<li>
<NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
</li>
<li>
<NavLink to="/user" activeClassName="active">User PRofile</NavLink>
</li>
<li>
<NavLink to="/register" activeClassName="active">Register</NavLink>
</li>
</ul>
</nav>
</div>
}
</>
)
}
}
https://repl.it/repls/IncredibleLinedCgi
This Will Work for You
Change this part of the code:
this.setState({
toggle : !this.state.toggle
});
To this:
this.setState(prev => {
return { toggle : !prev.toggle }
});
You should call getToggleState inside your setState callback in order to use proper state as argument
this.setState(prevState => {
this.props.getToggleState(!prevState.toggle);
return { toggle: !prevState.toggle };
});
Despite this solution, it's better if you don't keep duplicate state in child component <Header /> as conditional render is Parent duty.
This could be much simpler in my opinion.
Define the state on the parent component App ìsToggled
Call from the child component Header via callback this.props.onToggle()
Use conditional rendering on parent component {this.state.isToggled && <Sidebar/>}
import React, {Component} from 'react';
import {BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isToggled: false
}
};
onToggle = () => {
this.setState({
isToggled: !this.state.isToggled
});
console.log(this.state.isToggled);
};
render() {
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection: 'row'}}>
<div style={{flexDirection: 'column'}}>
<Header onToggle={this.onToggle}/>
</div>
{this.state.isToggled && <Sidebar/>}
</div>
</Router>
)
}
}
import React, {Component} from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<button onClick={() => {
this.props.onToggle()
}}>Toggle
</button>
</div>
)
}
}
import React, {Component} from 'react'
import {NavLink} from "react-router-dom";
export default class Sidebar extends Component {
render() {
return (
<div className="sidebar_container">
<nav className="nav_container">
<ul>
<li>
<NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
</li>
<li>
<NavLink to="/user" activeClassName="active">User PRofile</NavLink>
</li>
<li>
<NavLink to="/register" activeClassName="active">Register</NavLink>
</li>
</ul>
</nav>
</div>
)
}
}

React how to pass an state to another component

Hello i split my app and would like to pass the state from my <button />
to <menu /> I'm simply trying to do is toggle a function with an onClick.
So the Button.js file will have 1 buttons when clicked will toggle the states to visible or invisible. The menu component Menu.js will need know about these state changes so they can toggle the function and will show the menu
Button component
import React, { PureComponent } from 'react';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import { themr } from 'react-css-themr';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import localStyles from './NavButton.scss';
#themr('NavButton', localStyles)
export default class NavButton extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
};
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
this.setState({
visible: !this.state.visible
})
console.log('toggle');
}
render() {
const {theme } = this.props;
return (
<div className={theme['nav-button']} onClick={this.toggleMenu}>
<span></span>
<span></span>
</div>
);
}
}
Menu
import React, { PureComponent } from 'react';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import { themr } from 'react-css-themr';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import localStyles from './Menu.scss';
import { NavButton } from '../../components';
#themr('Menu', localStyles)
export default class Menu extends React.Component {
render() {
return (
<div className="menu-wrapper">
<CSSTransitionGroup
transitionName="menu"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}>
{this.state.visible &&
<Menus alignment="right">
<MenuItem hash="first-page">First Page</MenuItem>
<MenuItem hash="second-page">Second Page</MenuItem>
<MenuItem hash="third-page">Third Page</MenuItem>
</Menus>}
</CSSTransitionGroup>
</div>
);
}
}
const Menus = ({alignment, children, theme }) => (
<div className="menu">
<div className={alignment}>{children}</div>
</div>
);
Although you have imported Button component to Menu, you are not using it, Also what you should do is keep the state visible in the menu component and communicate to Menu from Button component like
export default class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
};
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
this.setState({
visible: !this.state.visible
})
console.log('toggle');
}
render() {
return (
<NavButton toggleMenu={this.toggleMenu}/>
<div className="menu-wrapper">
<CSSTransitionGroup
transitionName="menu"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}>
{this.state.visible &&
<Menus alignment="right">
<MenuItem hash="first-page">First Page</MenuItem>
<MenuItem hash="second-page">Second Page</MenuItem>
<MenuItem hash="third-page">Third Page</MenuItem>
</Menus>}
</CSSTransitionGroup>
</div>
);
}
}
const Menus = ({alignment, children, theme }) => (
<div className="menu">
<div className={alignment}>{children}</div>
</div>
);
Now you NavButton will be like
export default class NavButton extends React.Component {
render() {
const {theme } = this.props;
return (
<div className={theme['nav-button']} onClick={this.props.toggleMenu}>
<span></span>
<span></span>
</div>
);
}
}
It's better to maintain the state of an application at the top most component, so it kinda governs the brains of the app.
If you moved the state into the Menu, you can pass the onClick callback into the Button e.g.
Menu.js
<NavButton toggleClick={this.handleClick} />
Then you can move the State information into the Menu as well as the handleClick function.
This allows the Button to be stateless:
const NavButton = ({theme, toggleClick}) => (
<div className={theme['nav-button']} onClick={toggleMenu}>
<span></span>
<span></span>
</div>
);

React implementing react-sticky

I am trying to implement the following: https://www.npmjs.com/package/react-sticky
in my code as follow:
import React from 'react';
import Video from './../video.jsx';
import Overview from './overview.jsx';
import Photography from './photography.jsx';
import Details from './details.jsx';
import Cast from './cast.jsx';
import porgectsCollection from './../../data/projectInfo.js';
import { StickyContainer, Sticky } from 'react-sticky';
class Nav extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileMenu: false
};
}
showMobileMenu () {
this.setState({ mobileMenu: !this.state.mobileMenu });
}
render () {
let links = this.props.project.links.map(function(el, i){
return <li key={i}>{el}</li>;
});
const open = this.state.mobileMenu ? ' open' : '';
return (
<StickyContainer>
<span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
<Sticky topOffset={100} stickyClassName="sticky-nav">
<nav className={"secondary-nav" + open}>
<ul>
{links}
</ul>
</nav>
</Sticky>
</StickyContainer>
);
}
}
class SingleProject extends React.Component {
getProjectDataFromUrl() {
return porgectsCollection.filter(el => el.title === this.props.params.id);
}
render () {
let data = this.getProjectDataFromUrl(),
project = data[0];
console.log(project);
return (
<section className="project-page">
<Video project={project} />
<Nav project={project} />
<Overview project={project} />
<Photography project={project} />
<Details project={project} />
<Cast project={project} />
</section>
);
}
}
export default SingleProject;
I would hope that when "Sticky" reached 100px from the top it would get a custom class "sticky-nav" applied to it. However the nav keeps on scrolling without getting stuck at all. I can see the divs applied around my markup with the extra padding but no more then that.
URL project: https://github.com/WebTerminator/aldemar,
file in question is singleProject.jsx
import React from 'react';
import Video from './../video.jsx';
import Overview from './overview.jsx';
import Photography from './photography.jsx';
import Details from './details.jsx';
import Cast from './cast.jsx';
import porgectsCollection from './../../data/projectInfo.js';
import { StickyContainer, Sticky } from 'react-sticky';
class Nav extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileMenu: false
};
}
showMobileMenu () {
this.setState({ mobileMenu: !this.state.mobileMenu });
}
render () {
let links = this.props.project.links.map(function(el, i){
return <li key={i}>{el}</li>;
});
const open = this.state.mobileMenu ? ' open' : '';
return (
<Sticky stickyClassName="sticky-nav" topOffset={-100}>
<span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
<nav className={"secondary-nav" + open}>
<ul>
{links}
</ul>
</nav>
</Sticky>
);
}
}
class SingleProject extends React.Component {
getProjectDataFromUrl() {
return porgectsCollection.filter(el => el.title === this.props.params.id);
}
render () {
let data = this.getProjectDataFromUrl(),
project = data[0];
return (
<section className="project-page">
<StickyContainer>
<Video project={project} />
<Nav project={project} />
<Overview project={project} />
<Photography project={project} />
<Details project={project} />
<Cast project={project} />
</StickyContainer>
</section>
);
}
}
export default SingleProject;

Trying to use getCurrentContent in draftjs file

I want to get the content of my editor and eventually store to it to a const content. I'm getting an error of _draftJs.EditorState.getCurrentContent is not a function.
import React from 'react'
import ReactDOM from 'react-dom'
import {Editor, EditorState, RichUtils} from 'draft-js'
const content = EditorState.getCurrentContent()
console.log('str= ', EditorState.getCurrentContent())
console.log('content=', content)
class MyEditor extends React.Component {
constructor (props) {
super(props)
this.state = {editorState: EditorState.createEmpty()}
this.onChange = (editorState) => this.setState({editorState})
this.handleKeyCommand = this.handleKeyCommand.bind(this)
}
_onBoldClick () {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'))
}
_onUnderlineClick () {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'UNDERLINE'))
}
render () {
return (
<div id='content'>
<h1>Notejs</h1>
<div id='editor'>
<button onClick={this._onBoldClick.bind(this)}>Bold</button>
<button onClick={this._onUnderlineClick.bind(this)}>Underline</button>
<Editor editorState={this.state.editorState} onChange={this.onChange} />
</div>
</div>
)
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('app')
)
this.state.editorState.getCurrentContent() not EditorState.getCurrentContent()
import convertToRaw
convertToRaw(this.state.editorState.getCurrentContent())
Lets assume that we have a save button for saving data. Additionally we needs to import convertFromRaw and convertToRaw modules which are provided by draft-js.
import React from 'react'
import ReactDOM from 'react-dom'
import { Editor, EditorState, RichUtils, ContentState, convertFromRaw, convertToRaw} from 'draft-js';
class MyEditor extends React.Component {
constructor (props) {
super(props)
this.state = {editorState: EditorState.createEmpty()}
this.onChange = (editorState) => this.setState({editorState})
this.handleKeyCommand = this.handleKeyCommand.bind(this)
}
_onBoldClick () {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState,'BOLD'))
}
_onUnderlineClick () {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState,'UNDERLINE'))
}
_onSave() {
const contentState = this.state.editorState.getCurrentContent();
const editorContentRaw = convertToRaw(contentState);
/* we can save this editorContentRaw inside the DB. */
}
render () {
return (
<div id='content'>
<h1>Notejs</h1>
<div id='editor'>
<button onClick={this._onBoldClick.bind(this)}>Bold</button>
<button onClick={this._onUnderlineClick.bind(this)}>Underline</button>
<Editor editorState={this.state.editorState} onChange={this.onChange} />
<button onClick={this._onSave.bind(this)}>Save</button>
</div>
</div>
)
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('app')
)

Resources