I need my button (which is defined in Logout component) to be near to the Nav item.
When I call it, it would put it at the middle of the screen and won't consider the top and left defined in style.
This is Logout component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class LogOutButton extends Component {
static contextTypes = {
store: PropTypes.object.isRequired,
};
handleClick = () => {
this.props.onLogout();
};
render() {
const LogoutButtonStyle = {
color: 'black',
background: '#b7e1f7',
height: 50px,
width: 100px,
left: 10,
top: 10,
display:'inline-block'
}
return <button type="button" onClick={this.handleClick} style = {LogoutButtonStyle}>Back to Microsoft Give</button>;
}
}
Also, if I remove the 'top' and 'left', the button's location would still be the same.
This is the WholeScreen component in which I add logout component into:
render(){
.......
return(
<div className="WholeScreen">
<div>
<Nav bsStyle="pills" activeKey={this.state.year} onSelect={this.handleSelect} >
{buttons}
<LogoutButtonComponent onLogout={this.onLogoutClick}/>
</Nav>
</div>
<div>
<YearlySummary year={this.state.year} yearData={yearData}/>
</div>
</div>
);
}
}
I put the logout button inside the same with the navigation, but it would put the logout button at the center and not next to it.
Related
I am trying to make a menu that uses CSS3 to fade in and out when you click on the hamburger menu. I am using the react-hamburger-menu.
Although I can't figure out how to use the handleClick function and how to make it that when you click the menu button, or any of the links it triggers the toggle on the className.
I'm using the Gatsby react starter if that matters...
Here's what I have coded so far
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import './Header.css'
import { HamburgerMenu } from "react-hamburger-menu";
handleClick() {
this.setState({
open: !this.state.open
});
}
const Header = ({ siteTitle }) => (
<div className="Header">
<div className="HeaderGroup">
<Link to="/" className="logo"><img src={require('../../images/logo.svg')} width="70" alt="Ryan B. Designs"/></Link>
<HamburgerMenu
isOpen={this.state.open}
menuClicked={this.handleClick.bind(this)}
width={18}
height={15}
strokeWidth={1}
rotate={0}
color='black'
borderRadius={0}
animationDuration={0.5}
/>
</div>
<div className={"MainNavigation " + (this.state.open ? 'show' : 'hidden')}>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About Me</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</div>
</div>
)
Header.propTypes = {
siteTitle: PropTypes.string,
}
Header.defaultProps = {
siteTitle: ``,
}
export default Header
What I want to happen is when I click the hamburger button, the menu fades in, and when you click the close button or one of the links, the menu fades out using CSS3.
Beside the syntax error #JaromandaX pointed out in the comment, you're using setState in a function component. As it is right now, this doesn't have a setState, it's pointing to the module itself I believe. It should be point to a React class component that has state initiated:
class MyComponent extends React.Component {
// gatsby default environment supports class properties
state = {
isOpen: false,
}
handleClick = () => this.setState({ ... }) // this is now MyComponent
render() {
return (...)
}
}
or you can use useState hook.
I am trying to update state of my parent component through child component via setState. below is my parent component:
Fulllayout
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Header from '../components/header/header.jsx';
import Customizer from '../components/customizer/customizer';
import { Navbar, NavbarBrand, Collapse } from 'reactstrap';
export const settings = {
navbarbg: 'skin1',
sidebarbg: 'skin6',
logobg: 'skin6'
}
class Fulllayout extends React.Component {
constructor(props) {
super(props);
this.state = {
settings: settings
};
}
render() {
return (
<div id="main-wrapper">
<header data-navbarbg={this.state.settings.navbarbg}>
<Navbar expand="md" className={}></Navbar>
</header>
<div className="page-wrapper d-block"></div>
<Customizer />
</div>
);
}
}
export default Fulllayout;
in parent i have defined one constant settings which is exported. It is also given in the this.state. and in header, there is an attribute data-navbarbg={this.state.settings.navbarbg}.
I wanted to change its value dynamically. So, i have one customizer which is imported in parent as a child. Below is the child component:
customizer
import React from 'react';
import { settings } from '../../layouts/fulllayout';
import update from 'immutability-helper';
class Customizer extends React.Component {
constructor(props) {
super(props);
this.navbarbgChange = this.navbarbgChange.bind(this);
this.state = {
settings: settings
};
}
navbarbgChange(e) {
var skin = e.currentTarget.dataset.navbarbg;
var abc = update(this.state.settings, {
navbarbg: { $set: skin }
});
this.setState({ settings: abc });
}
render() {
return (
<aside className="customizer" id="customizer">
<a className="service-panel-toggle text-white"></a>
<div className="customizer-body pt-3">
<div className="mt-3 border-bottom px-3">
<ul className="theme-color mb-2">
<li><a data-navbarbg="skin1" onClick={this.navbarbgChange}></a></li>
</ul>
</div>
</div>
</aside>
);
}
}
export default Customizer;
From customizer, by clicking on color, i wanted to setState of parent to the value given in data-navbarbg attribute.
If i put this code in parent jsx file, it is working fine but for some reasons, this files should be kept separated.
So, what is missing in my code? or the whole approach is wrong? Thanks.
Is there a reason for navbarbgChange to be defined in Customizer?
You could consider moving navbarbgChange to Fulllayout instead.
That way you can do
<li><a data-navbarbg="skin1" onClick={this.props.navbarbgChange}></a></li>
This will ensure that the Fulllayout has the updated background in its state. This also ensures that there is good separation of concerns since settings is defined in the parent and not the child component
In react you can always pass methods from parent to child. Let's write method in the parent to change the state of the parent from the child like this.
class Fulllayout extends React.Component {
constructor(props) {
super(props);
this.state = {
settings: settings
};
}
// This will be passed to the child component
changeForCustomizerState() {
this.setState({
settings: abc
});
}
changeForHeaderState() {
this.setState({
settings: abc
});
}
render() {
return (
<div id="main-wrapper">
<header chageNavbarbg={this.changeForHeaderState}>
<Navbar expand="md" className={}></Navbar>
</header>
<div className="page-wrapper d-block"></div>
<Customizer chageNavbarbg={this.changeForCustomizerState} />
</div>
);
}
}
Then onClick on the child just call the parent method from the child which is passed from the parent.
render() {
return (
<aside className="customizer" id="customizer">
<a className="service-panel-toggle text-white"></a>
<div className="customizer-body pt-3">
<div className="mt-3 border-bottom px-3">
<ul className="theme-color mb-2">
<li><a data-navbarbg="skin1" onClick={this.props.chageNavbarbg}></a></li>
</ul>
</div>
</div>
</aside>
);
}
The state update can be done in Parent from Child using callbacks. Check below code for better understanding
Fulllayout:
updateState = (skin) => {
this.setState({
settings.navbarbg: skin
});
}
render(){
return(
<div>
<Customizer updateState={this.updateState}
</div>
);
}
And in your customizer
navbarbgChange(e){
const skin = e.currentTarget.dataset.navbarbg;
this.props.updateState(skin);
}
OR
Fulllayout:
updateState = (e) => {
const skin = e.currentTarget.dataset.navbarbg;
this.setState({
settings.navbarbg: skin
});
}
render(){
return(
<div>
<Customizer updateState={this.updateState}
</div>
);
}
Customizer: directly pass parent function to onClick
<li><a data-navbarbg="skin1" onClick={this.props.updateState}></a></li>
Also stop using var, and start using let and const mostly. ECMASCRIPT itself argues to avoid using var because of its window scope.
I am wondering if it is at all possible to fire an event in the grandchild and trigger something in the overall parent, without having to go through the middle step child.
I have created a simple example that will simply console.log the layer
So I am wanting to go Grandchild => Parent (Fire event) instead of going Grandchild => Child => Parent (Fire event)
If this is not possible in a simple way such as going up the chain, then do let me know.
Parent
export default class Parent extends React.Component {
render() {
return (
<div>
Parent
<Child clickMe={this.fireEvent.bind(this)}/>
</div>
)
}
fireEvent() {
console.log("Parent")
}
}
Child
export default class Child extends React.Component {
render() {
return(
<div>
child
<Grandchild fireEvent={this.handleClick.bind(this)}/>
</div>
)
}
handleClick() {
console.log('Child')
this.props.clickMe();
}
}
Grandchild
export default class Grandchild extends React.Component {
render() {
return(
<div>
grandchild
<button onClick={this.handleClick.bind(this)}>GC Click</button>
</div>
)
}
handleClick() {
console.log('Grandchild')
this.props.fireEvent();
}
}
To interact with components that are not direct children, you can use redux or context. Context is an experimental API and should be used if you have no other choice.
Here is an example:
import * as React from 'react';
import User from './User';
import PropTypes from 'prop-types';
class Small extends React.Component {
static contextTypes = {
color: PropTypes.string.isRequired,
user: PropTypes.object.isRequired
};
render() {
return <div style={{backgroundColor: this.context.color, height: '125px', width: '33%'}}>
Small, user = {this.context.user.id}-{this.context.user.login}
</div>;
}
}
class Medium extends React.Component {
render() {
return <div style={{backgroundColor: 'red', height: '250px', width: '50%'}}>
Medium
<Small/>
</div>;
}
}
export default class Large extends React.Component {
static childContextTypes = {
color: PropTypes.string.isRequired,
user: PropTypes.object.isRequired
};
getChildContext() {
return {color: 'purple', user: new User(1, 'admin')};
}
render() {
return <div style={{backgroundColor: 'blue', color: 'white', height: '300px', width: '75%'}}>
Large
<Medium/>
</div>;
}
}
I found that the way I had once seen is almost a cheating method of bypassing a certain layer, bu passing the parent props themselves as props within the child to the grandchild...
Parent
<child propsToChild={this.someFunction.bind(this)}/>
someFunction() { console.log("parent"); }
Child
<grandchild propsToGrandchild={this.props}/>
Grandchild
<button onClick={ this.grandChildClick.bind(this) }>Click me</button>
grandChildClick() {
console.log("Grandchild");
this.props.propsToGrandchild.propsToChild()
}
Demonstration
ALSO...
I have found that it is much easier to spread your props through the layers. This can be shown by editing the Child class as such:
render() {
const props = this.props;
return (
<div>
Child
<Grandchild {...props}/>
</div>
)
}
I have searched for 3 freaking days to find out how to toggle my mobile nav button to toggle my mobile menu. I am new to React and could do this easily with jQuery but I don't want to use jQuery. I have line for line copied an example that I found on how to show or hide an element. I can not get it to work. Any help would be much appreciated. I am using styled-components with React.
Button sub-component:
import React, { Component } from 'react';
class MenuButton extends Component {
render() {
return (
<Button onClick={this.props.toggleMenu}>
<Menu></Menu>
</Button>
)
}
}
export default MenuButton;
Menu sub-component:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class Menu extends Component {
render() {
return (
<OffCanvasMenu>
<Title>Menu</Title>
<Nav>
<NavLinks><Link to='/'>Home</Link></NavLinks>
<NavLinks><Link to='/about'>About</Link></NavLinks>
<NavLinks><Link to='/interactive'>Interactive</Link></NavLinks>
<NavLinks><Link to='/ideas'>Ideas</Link></NavLinks>
<NavLinks><Link to='/contact'>Contact</Link></NavLinks>
</Nav>
</OffCanvasMenu>
)
}
}
export default Menu;
Menu Container component with all the state:
import React, { Component } from 'react';
import Menu from './Menu';
import MenuButton from './MenuButton';
class MenuContainer extends Component {
constructor(props) {
super(props);
this.state = {
active: false
}
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
const { active } = this.state;
this.setState({
//toggle value of `active`
active: !active
});
}
render() {
return (
<div>
<MenuButton onClick={this.toggleMenu}/>
{this.state.active && <Menu/>}
</div>
)
}
}
export default MenuContainer;
I can see a checkbox in ReactDev tools that shows MenuContainer has state but when the button is clicked it does not toggle the state.
onClick is handled by MenuButton component which in turns invokes toggleMenu function passed as a property. I would pass toggleMenu as property of MenuButton:
<MenuButton toggleMenu={this.toggleMenu} />
I've a ButtonGroup as a radio buttons in navigation bar. I'd like to return a value of selected button in certain page. I've not much React experience and I'm a bit lost.
I have two .js-files: sidebar.js and page.js.
sidebar.js:
import React, { Component } from 'react';
import classNames from 'classnames';
import history from '../../core/history';
import {
Radio,
ButtonGroup,
Button } from 'react-bootstrap';
class Sidebar extends Component {
_onOptionChange(option) {
this.setState({
option: option
});
}
render() {
return (
<div>
...
...
...
<li>
<ButtonGroup vertical block data-toggle="buttons">
<Button className="btn btn-block" onClick={this._onOptionChange.bind(this, 'optionA')} active={this.state.option === 'optionA'}>Option A</Button>
<Button className="btn btn-block" onClick={this._onOptionChange.bind(this, 'optionB')} active={this.state.option === 'optionB'}>Option B</Button>
<Button className="btn btn-block" onClick={this._onOptionChange.bind(this, 'optionC')} active={this.state.option === 'optionC'}>Option C</Button>
</ButtonGroup>
</li>
...
...
...
</div>
);
}
}
export default Sidebar;
page.js:
import React, { PropTypes } from 'react';
import { PageHeader } from 'react-bootstrap';
const title = 'Page';
function displayPage(props, context) {
context.setTitle(title);
return (
<div>
<div className="row">
<div className="col-lg-12">
<PageHeader>Title</PageHeader>
</div>
<div className="col-lg-6">
{ value of selected radio button }
</div>
</div>
</div>
);
}
displayPage.contextTypes = { setTitle: PropTypes.func.isRequired };
export default displayPage;
How could I return the selected value?
Thanks!
From the React docs:
The state contains data specific to this component that may change over time.
In your Sidebar component, a click on the button will change the internal state of the Sidebar by calling this.setState({ ... }).
Consider the use of props when designing components:
Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.
So, in your case - I would think of Sidebar as a component that displays a list of options, and receives a callback function as its props. The callback function will be called from the Sidebar component by clicking one of the buttons, and will allow you to notify the containing component (the parent) of the click:
class SomethingThatUsesSidebar extends Component {
onSidebarOptionSelect(option) {
console.log(option);
}
render() {
return (
<div>
<Sidebar onOptionSelect={this.onSidebarOptionSelect.bind(this)} />
</div>
);
}
}
In your Sidebar component, you call the callback function like so:
class Sidebar extends Component {
// ...
_onOptionChange(option) {
this.props.onOptionSelect(option);
}
render() { ... }
}