I am using react-full-screen library.
Link to code sandbox
I have a navbar, where I have placed the JSX for the button with icons.
class AdminNavbar extends React.Component {
constructor(props) {
super(props);
this.state = {
isFfull: false
};
}
render() {
return (
<Navbar className="navbar" expand="lg">
<Container fluid>
<div className="navbar-wrapper">
<div className="navbar-minimize d-inline">
<button className="btn-fullscreen" onClick={this.props.goFull}>
<i className="fa fa-expand-arrows-alt"></i>
<i className="fa compress-arrows-alt"></i>
</button>
</div>
</div>
</Container>
</Navbar>
);
}
}
And then in my another Admin Component, I am using it as props and performing the onClick()
class Admin extends React.Component {
constructor(props) {
super(props);
this.state = {
isFull: false
};
}
goFull = () => {
if (document.body.classList.contains("btn-fullscreen")) {
this.setState({ isFull: true });
} else {
this.setState({ isFull: false });
}
document.body.classList.toggle("btn-fullscreen");
};
render() {
return (
<Fullscreen
enabled={this.state.isFull}
onChange={(isFull) => this.setState({ isFull })}
>
<div className="wrapper">
<div className="main-panel">
<AdminNavbar {...this.props} goFull={this.goFull} />
</div>
</div>
</Fullscreen>
);
}
}
Problem: the icons are not changing on click of the button. I also tried using the active class. but no luck.
You don't have to check the classList on body. The icon toggle can be achieved by state change.Please have a look at the code.
import React from "react";
import AdminNavbar from "./AdminNavbar";
import Fullscreen from "react-full-screen";
class Admin extends React.Component {
constructor(props) {
super(props);
this.state = {
isFull: false
};
}
goFull = () => {
this.setState({ isFull: !this.state.isFull });
};
render() {
return (
<Fullscreen
enabled={this.state.isFull}
onChange={(isFull) => this.setState({ isFull })}
>
<div className="wrapper">
<div className="main-panel">
<AdminNavbar
{...this.props}
isFull={this.state.isFull}
goFull={this.goFull}
/>
</div>
</div>
</Fullscreen>
);
}
}
export default Admin;
The admin Navbar code
import React from "react";
// reactstrap components
import { Navbar, Container } from "reactstrap";
class AdminNavbar extends React.Component {
constructor(props) {
super(props);
this.state = {
isFfull: false
};
}
render() {
return (
<Navbar className="navbar" expand="lg">
<Container fluid>
<div className="navbar-wrapper">
<div className="navbar-minimize d-inline">
<button className="btn-fullscreen" onClick={this.props.goFull}>
{!this.props.isFull ? (
<i className="fa fa-expand-arrows-alt"></i>
) : (
<i className="fa compress-arrows-alt"></i>
)}
</button>
</div>
</div>
</Container>
</Navbar>
);
}
}
export default AdminNavbar;
Related
I'm trying to pass props to a component from another component with React Router v4, but I'm not getting the result I want.
This is how I'm trying to pass props:
render() {
const { selectedLanguage, repos, error, dashboard } = this.state
return (
<React.Fragment>
<LanguagesNav
selected={selectedLanguage}
onUpdateLanguage={this.updateLanguage}
/>
{error && <p>{error}</p>}
{repos && <LoginForm repos={repos} selected={selectedLanguage} dashboard={dashboard} onUpdateLogin={this.updateLogin} />}
<Route
path='/dashboard'
render={(props) => (
<Dashboard {...props}
repos={repos}
selected={selectedLanguage}
/>
)}
/>
</React.Fragment>
The whole component I want to send props from:
Login.js
import React from 'react'
import PropTypes from 'prop-types'
import languagesdata from '../languagesdata.json'
import { fetchLanguageRepos } from '../utils/api'
import Dashboard from './Dashboard'
import {BrowserRouter as Router, Route } from 'react-router-dom'
import { Link } from 'react-router-dom'
function LanguagesNav ({ selected, onUpdateLanguage}) {
const languages = ['EU', 'ES', 'EN']
return (
<div >
<h1 className='center-text header-lg'>
GAUR 2.0
</h1>
<ul className='flex-center'>
{languages.map((language) => (
<li key={language}>
<button
className='btn-clear nav-link'
style={language === selected ? { color: 'rgb(187, 46, 31)' } : null }
onClick={() => onUpdateLanguage(language)}>
{language}
</button>
</li>
))}
</ul>
</div>
)
}
LanguagesNav.propTypes = {
selected: PropTypes.string.isRequired,
onUpdateLanguage: PropTypes.func.isRequired
}
function LoginForm ({ repos, selected, dashboard, onUpdateLogin }) {
var language = {}
switch (selected) {
case "EU":
selected = "EU";
language = repos[0].terms;
break;
case "ES":
selected = "ES";
language = repos[1].terms;
break;
case "EN":
selected = "EN";
language = repos[2].terms;
break;
}
return (
<form className='column player'>
<div className='row player-inputs'>
<input
type='text'
id='username'
className='input-light'
placeholder={language.username}
autoComplete='off'
/>
</div>
<div className='row player-inputs'>
<input
type='password'
id='password'
className='input-light'
placeholder={language.password}
autoComplete='off'
/>
</div>
<div className='row player-inputs'>
<Link
className='btn dark-btn'
to={{
pathname: '/dashboard',
}}
>
{language.login}
</Link>
</div>
</form>
)
}
LoginForm.propTypes = {
repos: PropTypes.array.isRequired
}
export default class Login extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedLanguage: 'EU',
repos: null,
error: null,
dashboard: false
}
this.updateLanguage = this.updateLanguage.bind(this)
}
componentDidMount () {
this.updateLanguage(this.state.selectedLanguage)
}
updateLanguage (selectedLanguage) {
this.setState({
selectedLanguage,
error: null
})
fetchLanguageRepos(selectedLanguage)
.then((repos) => this.setState({
repos,
error: null,
}))
.catch(() => {
console.warn('Error fetching repos: ', error)
this.setState({
error: 'There was an error fetching the repositories.'
})
})
}
render() {
const { selectedLanguage, repos, error, dashboard } = this.state
return (
<React.Fragment>
<LanguagesNav
selected={selectedLanguage}
onUpdateLanguage={this.updateLanguage}
/>
{error && <p>{error}</p>}
{repos && <LoginForm repos={repos} selected={selectedLanguage} dashboard={dashboard} onUpdateLogin={this.updateLogin} />}
<Route
path='/dashboard'
render={(props) => (
<Dashboard {...props}
repos={repos}
selected={selectedLanguage}
/>
)}
/>
</React.Fragment>
)
}
}
And this is the component I want to send props to:
Dashboard.js
import React from 'react'
import PropTypes from 'prop-types'
import Card from './Card'
import Loading from './Loading'
import { fetchLanguageRepos } from '../utils/api'
import Profile from './Profile'
import { Link } from 'react-router-dom'
function ReposGrid ({ repos, selected, profile, onUpdateProfile }) {
var language = {}
switch (selected) {
case "EU":
selected = "EU";
language = repos[0].terms;
break;
case "ES":
selected = "ES";
language = repos[1].terms;
break;
case "EN":
selected = "EN";
language = repos[2].terms;
break;
}
return (
<ul className='grid space-around'>
<li key={language.studyplan}>
<button
onClick={() => {onUpdateProfile(`${profile}`)}}
>
<Card
header={language.studyplan}
>
</Card>
</button>
</li>
<li key={language.careers}>
<Link to='/'>
<Card
header={language.careers}
>
</Card>
</Link>
</li>
<li key={language.census}>
<Card
header={language.census}
>
</Card>
</li>
<li key={language.sms}>
<Card
header={language.sms}
>
</Card>
</li>
<li key={language.tuitions}>
<Card
header={language.tuitions}
>
</Card>
</li>
<li key={language.surveys}>
<Card
header={language.surveys}
>
</Card>
</li>
<li key={language.titles}>
<Card
header={language.titles}
>
</Card>
</li>
<li key={language.exams}>
<Card
header={language.exams}
>
</Card>
</li>
<li key={language.record}>
<Card
header={language.record}
>
</Card>
</li>
</ul>
)
}
export default class Dashboard extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedLanguage: 'EU',
repos: null,
error: null,
loading: true,
profile: false
}
this.updateProfile = this.updateProfile.bind(this)
}
componentDidMount () {
var { repos, selectedLanguage } = this.props
this.setState({
selectedLanguage,
repos,
error: null,
loading: false,
profile: false
})
}
updateProfile (profile) {
this.setState({
error: null,
profile: true
})
}
render() {
const { selectedLanguage, repos, error } = this.props
const { profile } = this.state
if (profile === true) {
return (
<React.Fragment>
{repos && <Profile repos={repos} selectedLanguage={selectedLanguage} />}
</React.Fragment>
)
}
return (
<React.Fragment>
{repos && <ReposGrid repos={repos} selected={selectedLanguage} profile={profile} onUpdateProfile={this.updateProfile} />}
</React.Fragment>
)
}
}
I should be getting something like this:
Instead, I'm getting this:
Just to give more information, this is my index.js where I have set a route for Login.js:
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import Login from './components/Login'
import Dashboard from './components/Dashboard'
import Nav from './components/Nav'
import {BrowserRouter as Router, Route } from 'react-router-dom'
class App extends React.Component {
render() {
return (
<Router>
<div className='container'>
<Nav />
<Route exact path='/' component={Login} />
</div>
</Router>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
I've tried setting the route in index.js, but it didn't work either. What's the correct way to do it?
I am new to React and I am trying to make a simple application...I fetch some data from backend( a list with announces) and I make a list with them. So, I want that when I push to a button from that announce I want to go to another component where I can see details about that announce. I put my code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
carData: null,
checkData: false
}
}
getData = () => {
fetch('http://localhost:8000/api/all-articles')
.then( (response) => response.json() )
.then( (response) => {this.setState({
carData : response,
checkData : true
})});
}
componentDidMount = () => {
this.getData();
}
displayCars = () => {
return(
this.state.carData.data.map( (object, index) => (
<CarCard key={index} name = {object.title} description={object.description} img={object.image} id={object.id}/>
) )
);
}
render() {
if(this.state.checkData){
return(
<div className="App">
<Title/>
<div className="cars">
{this.displayCars()}
</div>
</div>
);
}else {
return(
<div>Loading..</div>
);
}
}
}
export default App;
class CarCard extends React.Component {
render() {
console.log(this.goToCardInfo(this.props.id));
return(
<div className="card">
<Card>
<Card.Img variant="top" src={`http://localhost:8000/images/${this.props.img}`}/>
<Card.Body>
<Card.Title>{this.props.name}</Card.Title>
<Card.Text>
{this.props.description}
</Card.Text>
<Button variant="primary">See announce</Button>
</Card.Body>
</Card>
</div>
);
}
}
export default CarCard;
class InfoCard extends React.Component {
render() {
return(
<h2>hello</h2>
);
}
}
export default InfoCard;
I want to say that from backend I fetch id, title,description, price..I googled it but I didn't understand how can I make it..Thank you
I think you need react-router-dom
I recommend you learn it. Below is my implementation with router.
App.js
import {BrowserRouter as Router, Switch, Route} from "react-router-dom"
import Cars from "./Cars.js" // Change it to the correct path
import InfoCard from "./InforCard.js"
class App extends React.Component {
render() {
<Router>
<Switch>
<Route path="/cars" component={Cars}></Route>
<Route path="/cars/:id" component={InfoCard} exact></Router>
<Switch>
</Router>
}
}
export default App;
Cars.js
class Cars extends React.Component {
constructor(props) {
super(props);
this.state = {
carData: null,
checkData: false
}
}
getData = () => {
fetch('http://localhost:8000/api/all-articles')
.then( (response) => response.json() )
.then( (response) => {this.setState({
carData : response,
checkData : true
})});
}
componentDidMount = () => {
this.getData();
}
displayCars = () => {
return(
this.state.carData.data.map( (object, index) => (
<CarCard key={index} name = {object.title} description={object.description} img={object.image} id={object.id}/>
) )
);
}
render() {
if(this.state.checkData){
return(
<div>
<Title/>
<div className="cars">
{this.displayCars()}
</div>
</div>
);
}else {
return(
<div>Loading..</div>
);
}
}
}
export default Cars;
CarCard.js
import { withRouter } from "react-router-dom"
class CarCard extends React.Component {
render() {
console.log(this.goToCardInfo(this.props.id));
return(
<div className="card">
<Card>
<Card.Img variant="top" src = {`http://localhost:8000/images/${this.props.img}`}/>
<Card.Body>
<Card.Title>{this.props.name}</Card.Title>
<Card.Text>
{this.props.description}
</Card.Text>
<Button variant="primary"
onClick={() => this.props.history.push("/card/" + this.props.id)}>See announce</Button>
</Card.Body>
</Card>
</div>
);
}
}
export default withRouter(CarCard);
InfoCard.js
class InfoCard extends React.Component {
// you can get the id of the card like this
const url = window.location.hash;
const id = url.substring(url.lastIndexOf("/") + 1);
// use that id to query your car
render() {
return(
<h2>hello</h2>
);
}
}
export default InfoCard;
According to react docs
the code below will re-render all consumers every time the Provider re-renders because a new object is always created for value
So i made a simple example to test this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
console.log('App');
return (
<>
<ThemeContext.Provider value={this.state.value}>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</>
);
}
handler=()=>{
this.forceUpdate()
}
}
const app = <App />;
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app,mountNode);
It seems that in every click, even though the reference is the same, toolbar component re-renders along with provider. So what is wrong here?
Writing the consumer as direct children of App will cause them to render when App component re-renders instead you must write your code as
const ThemeContext = React.createContext();
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
console.log('App');
return (
<React.Fragment>
<ThemeContext.Provider value={this.state.value}>
{this.props.children}
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</React.Fragment>
);
}
handler=()=>{
this.forceUpdate()
}
}
const app = (<App>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</App>)
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<div id="app"/>
try this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
handler(){
this.forceUpdate()
}
render() {
console.log('App');
return (
<div>
<ThemeContext.Provider value={this.state.value}>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</div>
);
}
}
const app = <App />;
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app,mountNode);
In my main component I can open a modal by clicking on an icon. The content of the modal is a separate component, which is calling a method.
If the method call is successful, I want to close the modal. But how can I do this?
Main component
class Example extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<div>
<Modal trigger={ <Icon name='tags' /> } >
<Modal.Header>
<div>
<Header floated='left'>Title</Header>
<Button floated='right'>A Button</Button>
</div>
</Modal.Header>
<Modal.Content>
<ModalContent />
</Modal.Content>
</Modal>
</div>
)
}
}
Modal content
class ModalContent extends Component {
constructor(props) {
super(props)
this.state = {}
}
handleClick() {
method.call(
{ param },
(error, result) => {
if (result) {
// Now close the modal
}
}
);
}
render() {
return (
<Button onClick={this.handleClick} content='Save' />
)
}
}
You should add an onClose property to <Modal> element. See example below:
<Modal
trigger={<Button onClick={this.handleOpen}>Show Modal</Button>}
open={this.state.modalOpen}
onClose={this.handleClose}
>
Then you can add onClose function to a button in your modal. Full example from the docs:
https://react.semantic-ui.com/modules/modal#modal-example-controlled
Pass a onSuccess method as a props :
in the parent :
<ModalContent onSuccess={this.onModalSuccess}/>
in the child component :
handleClick() {
method.call(
{ param },
(error, result) => {
if (result) {
this.props.onSuccess()
}
}
);
}
In this way you keep your open/close logic in the parent component.
semantic-ui have property open. Just set true or false
class Example extends Component {
constructor(props) {
super(props)
this.state = {
open: false
}
open = () => this.setState({ open: true })
close = () => this.setState({ open: false })
render() {
return (
<div>
<Modal open={this.state.open} trigger={ <Icon name='tags' /> } >
<Modal.Header>
<div>
<Header floated='left'>Title</Header>
<Button floated='right'>A Button</Button>
</div>
</Modal.Header>
<Modal.Content>
<ModalContent />
</Modal.Content>
</Modal>
</div>
)
}
}
Hi guys I want to create a new SideMenu component based on OnsenUI splitterSide demo I try this but I don't know how I can manage my sates and props. I'm new in React.js. Can someone help me to improve (fix) this?
This is my component code now:
import React, { PropTypes, Component } from 'react';
import { Page, Icon, List, ListItem, Splitter, SplitterSide, SplitterContent} from 'react-onsenui';
import page1 from '../pages/page1.jsx';
import page2 from '../pages/page2.jsx';
class SideMenu extends Component {
constructor(props) {
super(props);
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
this.page1 = this.page1.bind(this);
this.page2 = this.page2.bind(this);
};
hide() {
this.props.isOpen = false;
};
show() {
this.props.isOpen = true;
};
goto_page1() {
this.props.navigator.resetPage({
component: page1,
key: 'Page1_Index'
});
};
goto_page2() {
this.props.navigator.resetPage({
component: page2,
key: 'Page2_Index'
});
};
render() {
return (
<Splitter>
<SplitterSide
style={{
boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)'
}}
side='left'
width={200}
collapse={true}
isSwipeable={true}
isOpen={this.props.isOpen}
onClose={this.hide}
onOpen={this.show}
>
<Page>
<List
dataSource={['page one', 'page two']}
renderRow={(title) => {
switch(title) {
case "page one":
return (
<ListItem key={title} onClick={this.goto_page1} tappable>
<div>{title}</div>
</ListItem>
);
break;
case "page two":
return (
<ListItem key={title} onClick={this.goto_page2} tappable>
<div>{title}></div>
</ListItem>
);
break;
default:
return (
<ListItem key={title} onClick={this.hide} tappable>
<div>{title}</div>
</ListItem>
);
break;
}
}}
/>
</Page>
</SplitterSide>
<SplitterContent>
{this.props.children}
</SplitterContent>
</Splitter>
);
}
}
SideMenu.propTypes = {
navigator: PropTypes.object
};
export default SideMenu;
And this is Page1 code:
import React, { PropTypes, Component } from 'react';
import { Page, Toolbar, ToolbarButton, Icon} from 'react-onsenui';
import SideMenu from '../components/SideMenu.jsx';
class page1 extends Component {
constructor(props) {
super(props);
this.renderToolbar = this.renderToolbar.bind(this);
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
this.state = {
isOpen: false
};
};
renderToolbar() {
return (
<Toolbar>
<div className='left'>
<ToolbarButton onClick={this.show}>
<Icon icon='ion-navicon, material:md-menu' />
</ToolbarButton>
</div>
<div className='center'>Page One Title</div>
</Toolbar>
);
};
hide() {
this.setState({isOpen: false});
};
show() {
this.setState({isOpen: true});
};
render() {
return (
<SideMenu navigator={this.props.navigator} isOpen={this.state.isOpen}>
<Page renderToolbar={this.renderToolbar}>
Page content here
</Page>
</SideMenu>
);
}
}
page1.propTypes = {
navigator: PropTypes.object
};
export default page1;
Is my code style is correct? (is my props is states valid?)
How to prevent two time declaration of show and hide function?
New Version:
I change my code as bellow any idea or improvement??
import { Meteor } from 'meteor/meteor';
import React, { PropTypes, Component } from 'react';
import { Page, Icon, List, ListItem, Splitter, SplitterSide, SplitterContent, Toolbar, ToolbarButton, Modal} from 'react-onsenui';
import { Random } from 'meteor/random';
import page1 from '../pages/page1.jsx';
import page2 from '../pages/page2.jsx';
class SideMenu extends Component {
constructor(props) {
super(props);
this.renderToolbar = this.renderToolbar.bind(this);
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
this.goto_page1 = this.goto_page1.bind(this);
this.goto_page2 = this.goto_page2.bind(this);
this.state = {
isOpen: false
};
};
renderToolbar() {
return (
<Toolbar>
<div className='left'>
<ToolbarButton onClick={this.show}>
<Icon icon='ion-navicon, material:md-menu' />
</ToolbarButton>
</div>
<div className='center'>{this.props.pageTitle}</div>
</Toolbar>
);
};
hide() {
this.setState({isOpen: false});
};
show() {
this.setState({isOpen: true});
};
goto_page1() {
this.props.navigator.resetPage({
component: page1,
key: 'Page1_Index'
});
};
goto_page2() {
this.props.navigator.resetPage({
component: page2,
key: 'Page2_Index'
});
};
render() {
return (
<Splitter>
<SplitterSide
style={{
boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)'
}}
side='left'
width={200}
collapse={true}
isSwipeable={true}
isOpen={this.state.isOpen}
onClose={this.hide}
onOpen={this.show}
>
<Page>
<List
dataSource={[ 'page one', 'page two']}
renderRow={(title) => {
switch(title) {
case "page one":
return (
<ListItem key={title} onClick={this.goto_page1} tappable>
<div className='left'>{title}</div>
</ListItem>
);
break;
case "page two":
return (
<ListItem key={title} onClick={this.goto_page2} tappable>
<div className='left'>{title}</div>
</ListItem>
);
break;
default:
return (
<ListItem key={title} onClick={this.hide} tappable>
<div className='left'>{title}</div>
</ListItem>
);
break;
}
}}
/>
</Page>
</SplitterSide>
<SplitterContent>
<Page renderToolbar={this.renderToolbar} >
{this.props.children}
</Page>
</SplitterContent>
</Splitter>
);
}
}
SideMenu.propTypes = {
navigator: PropTypes.object.isRequired,
pageTitle: PropTypes.string.isRequired
};
export default SideMenu;
I also change my Page1 to:
import React, { PropTypes, Component } from 'react';
import { Icon, List, ListItem, ListHeader} from 'react-onsenui';
import SideMenu from '../components/SideMenu.jsx';
class page1 extends Component {
render() {
return (
<SideMenu navigator={this.props.navigator} pageTitle="page 1 title">
Page content here
</SideMenu>
);
}
}
page1.propTypes = {
navigator: PropTypes.object
};
export default page1;
How to prevent two time declaration of show and hide function?
You could use your methods this way:
<YourComponent method={ () => this.hide() }
And then you won't need the binding in the c-tor.
Or use a library called "autobind-decorator” and add #autobind before each class:
#autobind
class YourComponent extends React.Component {….}