I got a simple vertical nav panel which nav sections consist of image to the left and some text to the right. It looks like the following:
The code of the nav section is as follows:
import React from 'react';
import { connect } from 'react-redux';
import data from '../../data/data.json'
export default class TopBarMenuItems extends React.Component {
constructor(props) {
super(props);
}
render() {
const MENUITEMS = data.menuData.map((item) => { //pls note use of loop here
let srcPath = require(`../../image/topBarMenuIcons/${item.src}`);
return (
<div className="menuItem" dataset={item.id}>
<a href={item.url} className="topbarLink">
<div>
<img src={srcPath} />
</div>
{item.name}
</a>
</div>
)
});
return MENUITEMS;
}
};
The problem is that when I click on the text (some link 1) I get redirected to the desired page, but when I click on the image, I dont. So the ideas is to get redirected to the same page when either image or text is clicked. Any ideas how to fix it would be welcome?
Thank you.
You can use react-router-dom library
import React from 'react';
import { connect } from 'react-redux';
import data from '../../data/data.json'
import { Link } from 'react-router-dom'
export default class TopBarMenuItems extends React.Component {
constructor(props) {
super(props);
}
render() {
const MENUITEMS = data.menuData.map((item) => {
let srcPath = require(`../../image/topBarMenuIcons/${item.src}`);
return (
<div className="menuItem" dataset={item.id}>
<Link to={item.url} className="topbarLink">
<div>
<img src={srcPath} />
</div>
{item.name}
</Link>
</div>
)
});
return MENUITEMS;
}
};
Related
I am a beginner in React, and I would like to make a web app with a dashboard like Windows tiles.
I generate them easily. But I want when I click in one of them, that hide the Dash menu and Display the sub-app "Prog1". And of course, reverse it. When I click the close button, it closes the sub-app and returns to the Dash menu (implying that it hides the Prog1 to display Dash).
I can hide the Dash menu with a function like this:
fctHide = () => {
this.setState({ isActive: false });
}
But how can I display the other subApp with maybe a function like fctShow?
Are we forced to put the function inside a class or just make a general display/hide function?
Is there an easier and newer way to do this (with hooks for example).
My app is on Codepen here : codepen
I can show you here on demand.
I'm surprised to see lots of questions or tutorials to show and hide elements from a button but not to switch between class/HTML/template etc. (like React Native router I guess).
Thanks!
Unless you are converting an old app to React, i.e. not writing a pure React app from the ground up, don't use ReactDOM.render multiple times. As you want to share the active state between components, it should live in their closest common ancestor.
I'm not sure how your dashboard should work, but here's a demo. Here, APP is such closest ancestor. You don't need react-router if you are not using URL routes or the History API.
import React from "react";
import "./styles.css";
class Dash extends React.Component {
render() {
const { isActive, fctHide, fctShow } = this.props;
const elements = ["1", "2", "3", "4"];
const items = [];
for (const [index, value] of elements.entries()) {
items.push(
<button
key={index}
onClick={() => {
fctShow(index);
}}
>
{value}
</button>
);
}
// if (isActive) {
return (
<div>
<table>
<tbody>
<tr>
<td> {items} </td>
</tr>
</tbody>
</table>
</div>
);
// } else {
// return null;
// }
}
}
class Prog1 extends React.Component {
render() {
const { isActive, selected, fctHide } = this.props;
if (isActive) {
return (
<div className="contProg1">
<button onClick={fctHide}>Close</button>
<h1>Program 1</h1>
<h2>Test1</h2>
<h2>Test2</h2>
<h2>Test3</h2>
Selected: {selected}
<ul>
<li>AAAAA</li>
<li>BBBBB</li>
<li>CCCCC</li>
</ul>
</div>
);
} else {
return null;
}
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { isActive: true, selected: null };
}
fctShow = selected => {
this.setState({ isActive: true, selected });
};
fctHide = () => {
this.setState({ isActive: false });
};
render() {
const { isActive, selected } = this.state;
return (
<>
<Dash
isActive={isActive}
fctHide={this.fctHide}
fctShow={this.fctShow}
/>
<Prog1 isActive={isActive} selected={selected} fctHide={this.fctHide} />
</>
);
}
}
OK ! I finally use as proposed react-router. But I used the Hooks version (with <A>...)
So, the little dashboard is splitted in X parts :
The HTML with only the minimum and root.
<div id="root"></div>
The CSS (nothing to say more)
The sub apps in a specific folder "Apps"
import React from "react";
import { A } from "hookrouter";
class Prog1 extends React.Component {
render() {
return (
<div class="contProg1">
<button class="close">
{" "}
Close
</button>
<h1>Program 1</h1>
<h2>Test1</h2>
<h2>Test2</h2>
<h2>Test3</h2>
<ul>
<li>AAAAA</li>
<li>BBBBB</li>
<li>CCCCC</li>
</ul>
</div>
);
}
}
export default Prog1;
The router page to switch between apps and main Dash.
import React from "react";
import Prog1 from "./Apps/Prog1";
import Prog2 from "./Apps/Prog2";
import Prog3 from "./Apps/Prog3";
import Prog4 from "./Apps/Prog4";
import Dash from "./App";
const routes = {
"/": () => <Dash />,
"/Prog1": () => <Prog1 />,
"/Prog2": () => <Prog2 />,
"/Prog3": () => <Prog3 />,
"/Prog4": () => <Prog4 />
};
export default routes;
The main page, the Dashboard (App.js).
import React from "react";
import { A } from "hookrouter";
const elements = ["1", "2", "3", "4"];
function Dash() {
const items = [];
for (const [index, value] of elements.entries()) {
items.push(
<A href={"/Prog" + (index + 1)}>
<button key={index}>{value}</button>
</A>
);
}
return (
<div className="Dash">
<table>
<tr>
<td> {items} </td>
</tr>
</table>
</div>
);
}
export default Dash;
And to finish, the Index page :
import React from "react";
import { render } from "react-dom";
import "./styles.css";
import { useRoutes } from "hookrouter";
import routes from "./router";
import NoPageFound from "./Apps/404";
function App() {
const routeResult = useRoutes(routes);
return <div className="Dash">{routeResult || <NoPageFound />}</div>;
}
render(<App />, document.getElementById("root"));
It works well. I just need to add something like MemoryRouter or something else to hide the URL and prepare for mobile version.
I'm just a little bit scared when I will insert this part in a Django project.
Or, maybe I should separate it ? (You don't need to answer, I will close I think).
Thanks :)
This is my index.js file
Imports
import React from 'react';
import ReactDOM from 'react-dom';
import field from './images/field.jpg';
import forest from './images/forest.jpg';
import hills from './images/hills.jpg';
import lake from './images/lake.jpg';
import sunrise from './images/sunrise.jpg';
Image component
class Image extends React.Component {
render() {
return (
<div className="img-container">
<img src={this.props.images[this.props.index]} alt={this.props.images[this.props.index]} />
</div>
);
}
}
This is reusable button component
class Button extends React.Component {
render() {
return (
<button className="button" >{this.props.content}</button>
);
}
}
This is two sliders that use button component
class Slider extends React.Component {
render() {
return (
<div className="slider">
<Button content={"❮"} onClick={this.props.decreaseIndex}/>
<Button content={"❯"} onClick={this.props.increaseIndex}/>
</div>
);
}
}
This is the main carousel component that encapsulates all other components
class Carousel extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [field, forest, hills, lake, sunrise],
current: 0
}
}
changeIndex(what){
if (what > 0){
this.setState({
current: (this.state.current+1)%5
});
return;
}
this.setState({
current: (this.state.current-1)%5
});
}
increaseIndex(){
this.changeIndex(1);
}
decreaseIndex(){
this.changeIndex(-1);
}
render() {
return (
<div className="carousel">
<Image index={this.state.current} images={this.state.images}/>
<Slider clickPrev={this.decreaseIndex} clickNext={this.increaseIndex}/>
</div>
);
}
}
ReactDOM.render(<Carousel />, document.getElementById('root'));
I wanted to make a simple carousel using reactjs. It displays one image at a time, previous and next buttons change images. There are total 5 images to be displayed. On clicking 'next' or 'previous' button, images do not change as expected.
What is the exact mistake I am making here? I am new to react.
You have to bind your method changeIndex and the rest in your constructor. Like this:
constructor(props) {
super(props);
this.state = {
images: [field, forest, hills, lake, sunrise],
current: 0
}
this.changeindex = this.changeIndex.bind(this);
//other methods.
}
Read more in React Docs about events.
It is fixed,
Following changes were made:
Binding methods in constructor of Carousel class. Thanks to tksilicon's answer
In Slider class
<Button content={"❮"} work={this.props.decreaseIndex}/>
<Button content={"❯"} work={this.props.increaseIndex}/>
In Button
<button className="button" onClick={this.props.work}>{this.props.content}</button>
Good day!
I am new to React and html2canvas. I am making an app which will take "screenshots" of my DOM using html2canvas then store it to an array of screenshots which will then be also rendered on the screen.
I am storing each <canvas> object received from the html2canvas promise to an array then pass it to my ScreenshotsContainer component which passes the array to the Screenshots component. The Screenshots component will then map the array of <canvas> objects to individual Screenshot components.
In App.js, I am calling the html2canvas function then pass the array to ScreenshotsContainer component
import React, { Component } from 'react';
import ScreenshotsContainer from './containers/ScreenshotsContainer/ScreenshotsContainer'
import html2canvas from 'html2canvas';
import './App.css';
class App extends Component {
state = {
canvasArray: []
}
getScreenshotHandler = () => {
console.log("[Canvas Array from state length:]" + this.state.canvasArray.length)
let canvasArray = this.state.canvasArray;
html2canvas(document.body).then((canvas) => {
canvasArray.push(canvas)
});
console.log("[Canvas Object value: ]" + canvasArray);
this.setState({ canvasArray: canvasArray })
}
render() {
return (
<React.Fragment>
<button onClick={this.getScreenshotHandler}>Get Screenshot</button>
<ScreenshotsContainer canvasArray={this.state.canvasArray} />
</React.Fragment>
);
}
}
export default App;
The ScreenshotsContainer component will pass the received array to the Screenshots component:
import React, { Component } from 'react';
import './ScreenshotsContainer.css'
import Screenshots from '../../components/Screenshots/Screenshots';
class ScreenshotsContainer extends Component {
render() {
return (
<div className="ScreenshotsContainer">
<Screenshots canvasArray={this.props.canvasArray} />
</div>
);
}
}
export default ScreenshotsContainer;
The Screenshots component will map the array and pass each canvas object to the Screenshot component:
import React, { Component } from 'react';
import Screenshot from './Screenshot/Screenshot';
class Screenshots extends Component {
render() {
const screenshots = this.props.canvasArray.map(canvas => {
return (
<Screenshot
key={Math.random}
canvasObj={canvas}
/>
)
})
return (
<React.Fragment>
{screenshots}
</React.Fragment>
);
}
}
export default Screenshots;
Here is the Screenshot component
import React from 'react';
import './Screenshot.css';
const screenshot = (props) => (
<div className="Screenshot" >
<canvas ref={props.canvasObj} style={{
width: '10%',
height: '10%'
}} />
</div>
);
export default screenshot;
What I actually get when pressing the button:
Actual screenshot of my result
I was wondering which part went wrong. Any help would be appreciated.
This particular library works in a specific way (looks like it's doing a lot of "magic" under the hood - you should look at the source code here more specifically the renderer folder inside src)
Saving the canvas to the state inside of an array (the correct react way of doing things) will be a problem as it saves it as a complex object with many methods etc... and we can not render objects... This lib was not written with React in mind...
The code sample below is a simple implementation in React...
Here is a live demo: https://codesandbox.io/s/9y24vwn1py
import React, { Component } from 'react';
import html2canvas from 'html2canvas';
class App extends Component {
constructor(props) {
super(props);
this.captureRef = React.createRef();
this.displayRef = React.createRef();
}
getScreenshotHandler = () => {
html2canvas(this.captureRef.current).then(canvas =>
this.displayRef.current.appendChild(canvas),
);
};
render() {
return (
<div>
<div ref={this.captureRef}>
<h2>This enitre div will be captured and added to the screen</h2>
</div>
<button onClick={this.getScreenshotHandler}>Get Screenshot!</button>
<section>
<h5>Your screenshots will be availbale below</h5>
<div ref={this.displayRef} />
</section>
</div>
);
}
}
export default App;
EDIT: based on the comment below here is yet another workaround:
class App extends Component {
constructor(props) {
super(props);
this.state = { canvasArray: [] };
this.captureRef = React.createRef();
}
getScreenshotHandler = () => {
html2canvas(this.captureRef.current).then(canvas =>
this.setState({
canvasArray: [canvas.toDataURL(), ...this.state.canvasArray],
}),
);
};
renderCanvas = () => {
return this.state.canvasArray.map((canvas, i) => {
return <img key={i} src={canvas} alt="screenshot" />;
});
};
render() {
return (
<div className="wrapper">
<div ref={this.captureRef}>
<p>This enitre div will be captured</p>
</div>
<button onClick={this.getScreenshotHandler}>Get Screenshot!</button>
<section>
<h5>Your screenshots will be availbale below:</h5>
{this.renderCanvas()}
</section>
</div>
);
}
}
Link to live demo: https://codesandbox.io/s/1r213057vq
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} />
UPDATE: after restart it works now. However it stills shows the logged out component first then the logged in one. Why is this because the user is logged in I just refresh the page?
UPDATE 2:
It has gone back to the flashing of the logged out => then then what it should be and then to white again, after no changes just restarting meteor.
UPDATE 3:
So it works then I navigate to this page but not others.It seems because the registration page subscribes to the items collection so that is how it picks it up. I thought it should not refresh the Box component when changing pages and should be subscribed to the items collection from the Box component itself. This page is loaded via flow router and is inputted into the content area of the site see below:
import Items from '/imports/collections/items/items.js';
export default class Registration extends TrackerReact(React.Component){
constructor(){
super();
this.state = {
subscription: {
items: Meteor.subscribe("allStarterItems")
}
}
}
The main page is here, the issues lies within the LeftNavbar area as this contains the boxes:
import React from 'react';
import ReactDOM from 'react-dom';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import LeftNavbar from './LeftNavbar';
export const MainLayout = ({content}) => (
<div className="main-layout">
<LeftNavbar />
<div className="right content-page">
<main>
{content}
</main>
</div>
</div>
)
Here is the left navbar page:
import React from 'react';
import ReactDOM from 'react-dom';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import Box from '/imports/ui/left_navbar/Box';
export default class LeftNavbar extends TrackerReact(React.Component){
constructor(){
super();
}
render(){
return (
<div className="left side-menu">
<div className="body rows scroll-y">
<div className="sidebar-inner ">
<Box />
</div>
</div>
</div>
)
}
}
Hey everyone I have an issue in my project.
I have an area where I have a stack of images stacked on top of each other and are overlayed. I know the css etc work as I have it on another page just not loading from a db.
Here the the file that checks if the user is logged in or not to decide what component to render:
import React from 'react';
import ReactDOM from 'react-dom';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import BoxSignedIn from '/BoxSignedIn';
import BoxSignedOut from '/BoxSignedOut';
export default class Box extends TrackerReact(React.Component){
constructor(){
super();
}
render(){
var layout;
if (Meteor.user()) {
layout = <BoxSignedIn />;
} else {
layout = <BoxSignedOut />;
}
return (
layout
)
}
}
Here is the component that is loaded. However when I reload the page it shows the logged out component for a split second, then it shows nothing. On the source of the page it shows no src from the images. In the console it sometimes shows 2 of the image sources, sometimes 3
import React from 'react';
import ReactDOM from 'react-dom';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import Items from '/imports/collections/items/items.js';
export default class BoxSignedIn extends TrackerReact(React.Component){
constructor(){
super();
this.state = {
subscription: {
items: Meteor.subscribe("allStarterItems")
},
layers: {
layer1: Meteor.user().profile.layer.1,
layer2: Meteor.user().profile.layer.2,
layer3: Meteor.user().profile.layer.3
}
}
}
componentWillUnmount(){
this.state.subscription.items.stop();
}
getItemSource(itemKey){
var itemer = Items.findOne({key: itemKey});
if(!itemer){
return "";
}else{
console.log(itemer.srcEntire); // shows src correctly
return itemer.srcEntire;
}
}
render(){
return (
<div className="media" >
<div className="Area">
<div className="container-on-top box-small" >
<img id="layer1" className="on-top img-responsive center-block on-top" name="layer1" src={this.getItemSource(this.state.layers.layer1)} />
<img id="layer2" className="on-top img-responsive center-block on-top" name="layer2" src={this.getItemSource(this.state.layers.layer2)} />
<img id="layer3" className="on-top img-responsive center-block on-top" name="layer3" src={this.getItemSource(this.state.layers.layer3)} />
</div>
</div>
</div>
)
}
}