i want to change state different js but i can not , i have a sidebar.js with react-burger-menu
i want to call and change toggleMenu state in header.js
When I click the menu link, i want to toggle react-burger-menu but different js. this is not working.
sidebar.js
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
header.js have link for react-burger-menu
import React from 'react';
import PropTypes from 'prop-types';
import SidebarMenu from "../SidebarMenu";
export default class Header_Video extends React.Component {
render() {
return (
<Container>
<Row>
<Col md={5} sm={12} xs={12} className="text-left mobile-right">
<div className="bar__module">
<a onClick={this.toggleMenu}>Menu</a>
</div>
</Col>
</Row>
</Container>
);
}
}
thanks for help
note: i have a app.js all files import. I want to run toggleMenu in header.js
app.js
const TemplateWrapper = ({ children }) => (
<div id="outer-container">
<SidebarMenu />
<main id="page-wrap" className="page-wrap">
<HeaderVideo /> {children()}
<Footer />
</main>
</div>
);
menuOpen should be in a parent state of both components.
Example:
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
closeMenu = () => {
this.setState({menuOpen: false})
}
toggleMenu = () => {
this.setState({menuOpen: !this.state.menuOpen})
}
render() {
return (
<div>
<SidebarMenu isMenuOpen={this.state.menuOpen} toggleMenu={this.toggleMenu} />
<Header toggleMenu={this.toggleMenu} />
</div>
)
}
}
You may have further errors beyond just this, but the glaring error to me is that toggleMenu() is not bound to the constructor.
https://reactjs.org/docs/handling-events.html
try:
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
this.toggleMenu = this.toggleMenu.bind(this);
// the above statement binds the function to the object constructor
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
You'll also want to use an HTML5 button tag instead of a link tag, the correct HTML semantic structure provides a bunch of underlying features and greatly improves accessibility out of the box.
Also, remove the arrow function and pass a reference to the function, not the returned value. This is so react doesn't call the function immediately but stores the function reference to execute upon the click event.
<button onClick={this.toggleMenu}>Menu</button>
// instead of
<a onClick={() => this.toggleMenu()}>Menu</a>
Hope this helps!
Related
I am trying to understand how to pass props to components in react. I am new to react and I have been struggling to understand the fundamentals of state.
I would like a button to display an overlay and populate the "content" of that overlay with some arbitrary text for now.
I am trying to use a prop called doWeDisplay as variable to hold a css value of "none" or "absolute" (to hide and show the component) and a prop called "content" for the content of the overlay.
Here is my code, could someone please point me in the right direction. I need that eureka moment for it to click in place and my head is all over the place trying to get this.
app.js
import React from 'react';
import Overlay from './components/overlay';
import Header from './components/header';
import Body from './components/body';
import Footer from './components/footer';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
console.log("App props", this.props)
return (
<div className="App">
<Overlay />
<Header />
<Body content={ this.props.appContent } />
<Footer />
</div>
);
}
}
export default App;
body.js
import React from 'react';
import './body.css';
import Overlay from './overlay'
class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay : "absolute",
content : "Go on"
};
}
render() {
function handleClick(e) {
console.log("Click")
Overlay.setState((state, props) => ({
doWeDisplay : "absolute",
content : "Go on"
}))
}
console.log("Body props ", this.props);
return (
<div className="App-Body">
<p>Here is the body of the page.</p>
<button onClick={ handleClick }>Click me</button>
</div>
);
}
}
export default Body
overlay.js
import React from 'react';
import './overlay.css';
class Overlay extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay : props.doWeDisplay,
content : props.doWeDisplay
};
}
render() {
console.log("Overlay props " , this.props)
return (
<div className="App-Overlay" style={{ display: this.state.doWeDisplay }}>
{ this.state.content }
</div>
);
}
}
export default Overlay
When you have sibling components that can change other's state, you will need to handle that state in the parent component (in your case it is App).
So the handleClick() function should be in the parent component, and the state itself of the variables doWeDisplay and content should be in App as well.
Then, you can pass that function to Body as a prop, so you could trigger it on click within the Body component. I called that prop clickFunc in my example.
Finally, the last thing you will need is to pass the current state to Overlay as props, so I passed the doWeDisplay and content as different props, that gets the value from App's state.
It should look something like this:
app.js
import React from 'react';
import Overlay from './components/overlay';
import Header from './components/header';
import Body from './components/body';
import Footer from './components/footer';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay: "absolute",
content: "Go on"
};
}
handleClick = () => {
console.log("Click");
this.setState({
doWeDisplay: "absolute",
content: "Go on CHANGED!"
});
};
render() {
console.log("App props", this.props);
return (
<div className="App">
<Overlay
doWeDisplay={this.state.doWeDisplay}
content={this.state.content}
/>
<Body clickFunc={this.handleClick} content={this.props.appContent} />
</div>
);
}
}
export default App;
body.js
import React from 'react';
import './body.css';
import Overlay from './overlay'
class Body extends React.Component {
render() {
console.log("Body props ", this.props);
return (
<div className="App-Body">
<p>Here is the body of the page.</p>
<button onClick={() => this.props.clickFunc()}>Click me</button>
</div>
);
}
}
export default Body
overlay.js
import React from 'react';
import './overlay.css';
class Overlay extends React.Component {
render() {
console.log("Overlay props ", this.props);
return (
<div className="App-Overlay" style={{ display: this.props.doWeDisplay }}>
{this.props.content}
</div>
);
}
}
export default Overlay
Here's codesandbox
I am trying to display/hide one component which is ItemMain and which is imported to the main App component using button in another component which is NavLogoNew. I tried to do this in many different ways but it looks like the button doesn't know if it's clicked, when I change true/false manually it works. In web I found a lot of stuff about situations when only two components are involved, but nothing like this. My code:
App
import React from 'react';
import './App.css';
import { tsPropertySignature } from '#babel/types';
import { statement } from '#babel/template';
import NavBar from './../Components/Navigation/NavBar/NavBar.js';
import ItemMain from './../Components/Item/ItemMain/ItemMain.js';
import ItemList from './../Components/Item/ItemList/ItemList.js';
import NavButtonTop from './../Components/Navigation/NavButton/NavButtonTop/NavButtonTop.js';
import NavLogoNew from './../Components/Navigation/NavButton/NavButtonNew/NavLogoNew.js';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
visible: !this.visible
})
}
render() {
return (
<div className="App">
<NavBar />
{this.state.visible ? <ItemMain /> : null}
<ItemList />
<NavButtonTop name='UP'/>
</div>
);
}
}
export default App;
NavLogoNew:
import React from 'react';
import './NavLogoNew.css';
import ItemMain from './../../../Item/ItemMain/ItemMain.js'
class NavLogoNew extends React.Component {
render() {
return (
<button
className='NavLogoNew'
onClick={this.props.click}
>
{this.props.name}
</button>
);
}
}
export default NavLogoNew;
Your handleClick function is lacking something
use !this.state.visible so change from the below
handleClick(){
this.setState({
visible: !this.visible
})
}
to
handleClick = () => {
this.setState({
visible: !this.state.visible
})
}
pass the handleClick function to the NavLogoNew as follows
<NavLogoNew onClick = {this.handleClick} />
inside of the NavLogoNew component you should invoke it as follows
class NavLogoNew extends React.Component {
render() {
return (
<button
className='NavLogoNew'
onClick={() => this.props.onClick()}
>
{this.props.name}
</button>
);
}
}
I'm having trouble figuring out how to close a component that's rendered. I currently have am able to open the modal component on my first page, but then I want to close it upon the click of a button through the component. How would I do that?
import React, { Component } from 'react';
import AddModal from './addmodal';
class Page extends Component {
constructor(){
super();
this.state = { isModalOpen: false };
}
...//skip
handleAdd= () =>{
this.setState({ isModalOpen: true });
}
render(){
return (
<div>
<button onClick={this.handleAdd} > Add </button>
<AddModal isOpen={this.state.isModalOpen} />
</div>
)
}
}
import React, { Component } from 'react';
class AddModal extends Component {
// ... skip
handleClose = () => {
this.setState({ open: false });
};
render(){
return(
<modal inOpen={this.props.isOpen} >
<Button onClick={this.handleClose}>
Okay
</Button>
...//skip
</modal>
)
}
}
export default AddModal;
You need to make your modal component call an onClose callback so the parent can close it:
import React, { Component } from 'react';
import AddModal from './addmodal';
class Page extends Component {
constructor(){
super();
this.state = { isModalOpen: false };
}
...//skip
handleAdd= () =>{
this.setState({ isModalOpen: true });
}
handleClose= () =>{
this.setState({ isModalOpen: false });
}
render(){
return (
<div>
<button onClick={this.handleAdd} > Add </button>
<AddModal isOpen={this.state.isModalOpen} handleClose={this.handleClose}/>
</div>
)
}
}
import React, { Component } from 'react';
class AddModal extends Component {
// ... skip
render(){
return(
<modal inOpen={this.props.isOpen} >
<Button onClick={this.props.handleClose}> // call to parent
Okay
</Button>
...//skip
</modal>
)
}
}
export default AddModal;
The parent component will decide whether the modal is open or not, hence it owns the state of the child.
Building on what #jsdeveloper posted, I think you can cut the clutter by using the same function to handle the opening and closing of the modal.
We will make use of a toggleModal function which changes the isModalOpen to true when it's false and vice versa. It uses a callback, which takes in the previous state value of isModalOpen.
toggleModal = () => {
this.setState(prevState => ({
isModalOpen: !prevState.isModalOpen
}))
}
So the final file should look something like this.
import React, { Component } from 'react';
import AddModal from './addmodal';
class Page extends Component {
constructor() {
super();
this.state = {
isModalOpen: false
};
}
// ... //skip
toggleModal = () => {
this.setState((prevState) => ({
isModalOpen: !prevState.isModalOpen
}));
};
render() {
return (
<div>
<button onClick={this.handleAdd}> Add </button>{' '}
<AddModal
isOpen={this.state.isModalOpen}
toggleModal={this.toggleModal}
/>
</div>
);
}
}
import React, { Component } from 'react';
class AddModal extends Component {
// ... skip
render() {
return (
<modal inOpen={this.props.isOpen}>
<Button onClick={this.props.toggleModal}>Close</Button>
//... skip
</modal>
);
}
}
export default AddModal;
This is my code
import React, { Component } from "react";
import { render } from "react-dom";
class CView extends Component {
someFunc() {
alert(1);
}
render() {
return <div>Hello, there</div>;
}
}
class App extends Component {
getControl() {
this.cv = <CView />;
return this.cv;
}
render() {
return (
<div>
<h2 onClick={() => this.cv.someFunc()}>Click Me</h2>
{this.getControl()}
</div>
);
}
}
render(<App />, document.getElementById("root"));
Also available on https://codesandbox.io/s/k2174z4jno
When I click on the h2 tag, I get an error saying someFunc is not defined. How can I expose a function of a component so that other components can access it?
Thanks
I think that this.cv = <CView />; will not directly return instance of CView component.
onClick={() => {
console.log(this.cv instanceof CView); // false
this.cv.someFunc();
}}
But if you try to use refs you will access it.
class App extends Component {
constructor(props) {
super(props)
this.cv = React.createRef();
}
onClick() {
this.cv.current.someFunc();
}
render() {
return (
<div>
<h2 onClick={() => this.onClick()}>Click Me</h2>
<CView ref={this.cv} />
</div>
);
}
}
It is more "React way" though. https://codesandbox.io/s/vy61q9o8xy
For example, a component like this:
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
render() {
return (
<div className="App">
<BodyContent />
<BottomOne />
</div>
);
}
}
export default App;
I want to implement a function on BodyContent that unmount BottomOne and mounts BottomTwo instead, so when I activate the function, the code is reestructured to this:
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
render() {
return (
<div className="App">
<BodyContent />
<BottomTwo />
</div>
);
}
}
export default App;
I'm very new to React, so if there's a better way to do it, I'm open to suggestions, but I really need that end result, a function on BodyContent that unmounts BottomOne and mounts BottomTwo.
You can maintain a state which tells which component to render. Something roughly like this
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
changeBottomComponent = (comp) => {
this.setState({ showBottom: comp})
}
render() {
return (
<div className="App">
<BodyContent changeBottomComponent={this.changeBottomComponent}/>
{this.state.showBottom === 1 ? <BottomOne /> : <BotttomTwo />}
</div>
);
}
}
export default App;
To achieve that maintain a state variable in parent component (some kind of identifier for component) and use that state variable to render different component.
Along with that you also need to pass a function from parent to child and use that function to update the parent state value.
Like this:
class App extends Component {
constructor(){
super();
this.state={
renderOne: true,
}
this.update = this.update.bind(this);
}
update(){
this.setState({renderOne: false})
}
render() {
return (
<div className="App">
<BodyContent update={this.update}/>
{this.state.renderOne? <BottomOne /> : <BottomTwo/> }
</div>
);
}
}
Now inside BodyContent component call this.props.update() to render another component.
You can use state or props to render different components.
Example:
import React, {
Component
}
from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
constructor(props) {
super(props);
this.state = {
decider: false
};
}
render() {
const bottomContent = this.state.decider === true ? <BottomOne /> : <BottomTwo />;
return (
<div className="App">
<BodyContent />
{ bottomContent }
</div>
);
}
}
export
default App;
You can also directly use the components in the state and render them. Could be more flexible this way.
const BottomOne = () => <div>BottomOne</div>;
const BottomTwo = () => <div>BottomTwo</div>;
class Example extends React.Component {
constructor() {
super();
this.state = { show: BottomOne };
this.toggleComponent = this.toggleComponent.bind(this);
}
toggleComponent() {
// Use whatever logic here to decide.
let show = BottomOne;
if (this.state.show === BottomOne) {
show = BottomTwo;
}
this.setState({ show });
}
render() {
return (
<div>
<button onClick={this.toggleComponent}>Change</button>
<this.state.show />
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>