I have a very basic program that is supposed to hide a square when I button is pressed. Within the Game component, it seems to be updating fine whenever I press the button, and sends an alert whenever I press the button with the current visibility. But when I try to update the square's visibility, it doesn't work.
import React from "react"; import ReactDOM from "react-dom"; import "./index.css";
function Square(props) {
return (
<div className="square" style={{ visibility: props.visibility }}></div>
); }
function Button(props) {
return (
<button type="button" onClick={props.onClick}>
Click to hide square!
</button>
); }
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
visibility: "visible",
};
}
handleClick() {
this.setState({
visibility:
this.state.visibility == "visible" ? "hidden" : "visible",
});
alert(this.state.visibility);
}
render() {
return (
<div>
<Button
onClick={() => this.handleClick()}
visibility={this.state.visibility}
/>
<Square />
</div>
);
} }
ReactDOM.render(<Game />, document.getElementById("root"));
because your Square component doesn't add props visibility to control
import React from "react"; import ReactDOM from "react-dom"; import "./index.css";
function Square(props) {
return (
<div className="square" style={{ visibility: props.visibility, background:'red',width:'100px', height:'100px' }}></div>
); }
function Button(props) {
return (
<button type="button" onClick={props.onClick}>
Click to hide square!
</button>
); }
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
visibility: "visible",
};
}
handleClick() {
this.setState({
visibility:
this.state.visibility == "visible" ? "hidden" : "visible",
});
alert(this.state.visibility);
}
render() {
return (
<div>
<Button
onClick={() => this.handleClick()}
visibility={this.state.visibility}
/>
<Square visibility={this.state.visibility} />
</div>
);
} }
ReactDOM.render(<Game />, document.getElementById("root"));
Related
class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}> Cancel </button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log("hi")
}
render() {
return (
<div>
<UserForm onCancel={this._navigateToLogin.bind(this)}/>
</div>
);
}
}
ReactDOM.render(
<UserCreate/>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
import React from 'react'
import { withRouter } from 'react-router-dom';
import UserForm from './UserForm'
import UsersService from '../services/UsersService'
class UserCreate extends React.Component{
_navigateToLogin() {
this.props.history.push('/homepage');
}
async _saveUser(user) {
await UsersService.createUser(user);
this._navigateToLogin();
}
render() {
return(
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
onSubmit={this._saveUser.bind(this)}
/>
</div>
);
}
}
export default withRouter(UserCreate)
import React from 'react'
import {
Button
} from '#material-ui/core'
export default class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
this.state = {
...
}
_handleFormSubmit() {
const user = {
...
};
this.props.onSubmit(user);
}
_cancelForm() {
this.props.onCancel();
}
render () {
return (
<div style={{ width: '100%', height: 'auto', position: 'fixed', minWidth: '100%', minHeight: '100%', backgroundColor: '#50617C' }}>
<Button size="small" onClick={ this._cancelForm.bind(this) }>Back</Button>
<Button size="small" onClick={ this._handleFormSubmit.bind(this) }>Create</Button>
</div>
)
}
}
The error is present when I click the "Back" button on CreateAccountForm, it returns an error that says that the onCancel function is not a function. I'm sending it on the UserCreate by binding and I'm calling it on the function _cancelForm(). I was thinking that the error is that I'm missing something in the constructor according to some react documentation, I used before this method and it worked, right now I don't know what's happening.
The code you posted does not demonstrate the error, below is your code and it works just fine.
class UserForm extends React.Component {
constructor(props) {
super(props);
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}>
cancel
</button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log('in navigate login');
}
render() {
return (
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(
<UserCreate />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Can you provide a minimal snippet that reproduces the error you are getting?
You also don't need to bind the handler if you use arrow functions. For example:
_navigateToLogin = () => {//arrow function is automatically bound to this
console.log('in navigate login');
};
and
<UserForm onCancel={this._navigateToLogin} />
Editing for clarity: I cannot figure out how to dynamically create Boostrap Components using JSX in a react app. End goal is to get the new button in the "newBtnSpace" div when the first button is clicked. I have tried using show.hide methods, but those need to be hard coded. Trying to create buttons based off an array. code:
./components/newBSBtnSpaceFunc.js
import React, { Component } from 'react'
import { Button } from 'reactstrap'
export default function NewBSBtnFunc() {
let BtnArray = ["red", "blue", "green"].map((btn) => {
return React.createElement(
Button,
{variant: 'primary'},
'New Button',
{id: "newBtn"},
btn
)
}
./components/BSBtn.js
import React, { Component } from 'react'
import { Button } from 'reactstrap'
import NewBSBtnFunc from "./NewBSBtnFunc"
export default class BSBtn extends Component {
render() {
return (
<div>
<Button onClick={NewBSBtnFunc}>Click Me</Button>
<div id="newBtnSpace"></div>
</div>
)
}
}
App.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import BSBtn from "./components/BSBtn"
function App() {
return (
<div>
<BSBtn></BSBtn>
</div>
);
}
export default App;
github link: https://github.com/mollygilbert389/testingBootstrapBtn
You can conditionally show the new button by setting a state item (in this case showNewButton) to true in the onClick of the original button.
render() {
return (
<div>
<Button onClick={() => this.setState({ showNewButton: true }))}>Click Me</Button>
<div id="newBtnSpace">{ this.state.showNewButton && <Button variant="primary" id="newBtn">New Button</Button> }</div>
</div>
)
}
PS you've already successfully worked out how to create Bootstrap buttons in jsx:
<Button onClick={NewBSBtnFunc}>Click Me</Button>
onClick does not expect a return value so returning the new button won't do anything.
The way you have things organized makes it very difficult since you can't return anything from the function, and you can't modify state from outside the class. I would suggest moving your click handler into the component and using to to modify a state value that will show the second button.
Here is my suggestion:
import React, { Component } from 'react'
import { Button } from 'reactstrap'
export default class BSBtn extends Component {
state = {show: false}
handleClick = () => {
this.setState({ show: !this.state.show })
}
render() {
return (
<div>
<Button onClick={this.handleClick}>Click Me</Button>
<div id="newBtnSpace">
{this.state.show ?
<Button variant="primary" id="newBtn">New Button</Button>
: null}
</div>
</div>
)
}
}
Updated solution to your updated question:
class BSBtn extends React.Component {
state = {
show: false,
buttons: []
}
handleClick = () => {
this.setState({ show: !this.state.show })
}
handleAdd = () => {
this.setState({ buttons: [...this.state.buttons, (this.state.buttons.length + 1)] })
}
render() {
return (
<div>
<h3>Option 1</h3>
<button onClick={this.handleClick}>Click Me</button>
<div id="newBtnSpace">
{this.state.show ? [1,2,3].map((value) => (
<div>
<button>Button {value}</button>
</div>
))
: null}
</div>
<hr/>
<div style={{ marginTop: '30px' }}>
<h3>Option 2</h3>
<button onClick={this.handleAdd}>Click Me</button>
{this.state.buttons.map((value) => (
<div>
<button>Button {value}</button>
</div>
))}
</div>
</div>
)
}
}
ReactDOM.render(<BSBtn />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root' />
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>
)
}
}
I'm using conditional rendering to render a specific button, if the state.show = true.
The problem is, that, if show is not true, the anim is played, but the component is not removed (because the anim doesn't remove the component, it's just animating it.)
i'm using Material ui, aphrodite, react-magic
there's my code :
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Button from '#material-ui/core/Button'
import {StyleSheet, css} from 'aphrodite'
import { swap, vanishOut } from 'react-magic'
import vanishIn from 'react-magic/lib/bling/vanishIn';
const styles = StyleSheet.create({
magic: {
animationName: vanishIn,
animationDuration: '2s'
},
magicOut: {
animationName: vanishOut,
animationDuration: '2s'
}
});
class App extends Component {
constructor(props) {
super(props);
this.state = {show: true};
}
FalseState(){
this.setState({show:false});
}
render() {
const show = this.state.show
let buttonStart;
if(show===true){
buttonStart =
<div className={css(styles.magic)}>
<Button className="start" variant="raised" onClick={() => this.FalseState()}>Button</Button>
</div>;
} else {
buttonStart =
<div className={css(styles.magicOut)}>
<Button className="start" variant="raised" >Button</Button>
</div>;
}
return (
<div className="App">
{buttonStart}
</div>
);
}
}
export default App;
I tried to use another state variable to trigger a unmount of the component after the animation is over - using setTimeout.
Hope this helps :)
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Button from '#material-ui/core/Button';
import { StyleSheet, css } from 'aphrodite';
import { swap, vanishOut } from 'react-magic';
import vanishIn from 'react-magic/lib/bling/vanishIn';
const styles = StyleSheet.create({
magic: {
animationName: vanishIn,
animationDuration: '2s'
},
magicOut: {
animationName: vanishOut,
animationDuration: '2s'
}
});
class App extends Component {
constructor(props) {
super(props);
this.state = { show: true, unMount: false };
}
FalseState() {
this.setState({ show: false }, () => {
setTimeout(() => {
this.setState({ unMount: true });
}, 2000);
});
}
render() {
const show = this.state.show;
let buttonStart;
if (this.state.unMount) {
return null;
}
if (show === true) {
buttonStart = (
<div className={css(styles.magic)}>
<Button className="start" variant="raised" onClick={() => this.FalseState()}>
Button
</Button>
</div>
);
} else {
buttonStart = (
<div className={css(styles.magicOut)}>
<Button className="start" variant="raised">
Button
</Button>
</div>
);
}
return <div className="App">{buttonStart}</div>;
}
}
export default App;
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>
);