Create a component that abstracts logic (from existing code) - reactjs

I create this code:
import React from 'react'
import { range } from 'lodash'
const DIV_NUMBER = 5
export default class App extends React.Component {
constructor(props) {
super(props)
this.divs = []
}
handleScroll = divIdx => () => {
const divRef = this.divs[divIdx]
const left = divRef.scrollLeft
const top = divRef.scrollTop
this.divs.forEach(div => (div.scrollLeft = left))
this.divs.forEach(div => (div.scrollTop = top))
}
render() {
return (
<div style={{ border: '1px solid tomato' }}>
{range(DIV_NUMBER).map(i => {
return (
<div
key={i}
ref={divElem => (this.divs[i] = divElem)}
onScroll={this.handleScroll(i)}
style={{
width: 300,
height: 100,
margin: '2px',
overflow: 'auto',
border: '1px solid black',
}}
>
<div
style={{
width: 500,
height: 400,
}}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Scelerisque eu ultrices vitae auctor eu
augue ut lectus. In fermentum et sollicitudin ac orci. Velit sed ullamcorper morbi
tincidunt ornare. Auctor eu augue ut lectus arcu bibendum. Non nisi est sit amet.
Facilisis magna etiam tempor orci eu lobortis. Et tortor at risus viverra adipiscing
at in tellus integer. Lacus luctus accumsan tortor posuere ac ut consequat semper
viverra. Fermentum dui faucibus in ornare quam viverra orci sagittis. Porttitor eget
dolor morbi non. Pulvinar pellentesque habitant morbi tristique senectus et.
Tincidunt eget nullam non nisi est sit amet facilisis magna. Purus semper eget duis
at tellus at urna condimentum. Ipsum dolor sit amet consectetur adipiscing. Sit amet
aliquam id diam maecenas ultricies mi eget mauris. Faucibus scelerisque eleifend
donec pretium vulputate sapien nec sagittis. Tristique senectus et netus et
malesuada fames ac turpis. Egestas integer eget aliquet nibh. Enim ut tellus
elementum sagittis vitae. Urna condimentum mattis pellentesque id nibh tortor id
aliquet. Magna eget est lorem ipsum dolor. Felis imperdiet proin fermentum leo vel
orci porta. Eget egestas purus viverra accumsan in nisl nisi. Adipiscing commodo
elit at imperdiet. Facilisis magna etiam tempor orci eu lobortis. Volutpat est velit
egestas dui id ornare arcu odio. Praesent elementum facilisis leo vel fringilla.
Laoreet non curabitur gravida arcu ac tortor dignissim convallis aenean. Sodales ut
etiam sit amet nisl. Turpis massa tincidunt dui ut ornare. Viverra mauris in aliquam
sem fringilla ut morbi tincidunt augue.
</div>
</div>
)
})}
</div>
)
}
}
It works.
It creates 5 div elements, scrolling one of them, all the div scroll togheter. I use React references to do that.
What I would like to do now is creates a component that abstracts this logic.
I imagine something like that:
<ScrollDivs>
{range(DIV_NUMBER).map(i => {
return (
<div
key={i}
style={{
width: 500,
height: 400,
}}
>
all the text...
</div>
)
})}
</ScrollDivs>
So a magic component ScrollDivs that deals with logic.
Who uses this component does not have to worry about how it is done, he just needs to wrap the divs that wants to be able to scroll together inside this component.
How can I do? I don't know where to start.
Any help is appreciate

React.Children.map can help you to iterate over props.children and React.cloneElement can help with passing new props to children:
export default class ScrollDivsSync extends React.Component {
divs = [];
handleScroll = e => {
const { scrollTop, scrollLeft } = e.target;
this.divs.forEach(div => {
div.scrollLeft = scrollLeft;
div.scrollTop = scrollTop;
});
};
render() {
const { children } = this.props;
let i = 0;
const enhancedChildren = React.Children.map(children, child =>
React.cloneElement(child, {
onScroll: this.handleScroll,
ref: divElem => (this.divs[i++] = divElem)
})
);
return enhancedChildren;
}
}
This is a CodeSandbox with the example

Related

how to convert component to pdf using jspdf and htm2canvas

i am trying to build cv maker web application.and i need to convert componet to pdf file.
here my code
const handelDownload = () => {
html2canvas(componentRef.current).then(function (canvas) {
const divImage = canvas.toDataURL("image/png");
const pdf = new jsPDF();
pdf.addImage(divImage, "PNG", 0, 0);
pdf.save("download.pdf");
});
};
return (
<>
<h1>hello world</h1>
<div ref={componentRef}>
<h1 className="text-4xl bg-red-500">My Component</h1>
<p className="text-lg">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel
ipsum et velit posuere tempus sed ac ex. Vestibulum ante ipsum primis
in faucibus orci luctus et ultrices posuere cubilia curae; Integer
eget augue faucibus, placerat leo vitae, dignissim mi. Fusce id nibh
id risus congue consequat ac ut libero. Duis ut tincidunt turpis. Nam
scelerisque tortor in risus interdum consequat. Ut vel lectus sem.
Nulla hendrerit erat vel massa finibus, eget laoreet tellus ultrices.
Integer rhoncus lectus quis libero imperdiet, et viverra turpis
fermentum. Donec ullamcorper nisl eget felis dictum, at suscipit dolor
viverra. Etiam ullamcorper sem sit amet ante bibendum iaculis.
</p>
</div>
</>
problem is qulity of pdf is wrost and elements are not in the same position in the PDF as they are in the original component.
i also try reactpdf.

React Table with Material UI context menu

I am having trouble getting the Material UI Menu to work with React Table#v6.
I want to be able to right-click anywhere in the table (row, td) and show a context menu. This part is working.
But I also want to be able to continuously right-click other locations in the table and always show the context menu the cursor location. This is not working. Currently, you have to click-away to close the menu and then right-click again to re-open the menu.
In the Material UI demo this is working fine:
https://material-ui.com/components/menus/#context-menu
I adopted the example above to work with React Table, but it's not quite working as expected.
My example adoption:
https://codesandbox.io/s/aged-leaf-0nf6b?file=/src/index.js
Any Ideas how to get this to work as in the example?
This is because you added onContextMenu props to Td, not the table container.
Move onContext Menu to container div, like this:
<div onContextMenu={(e) => {
e.preventDefault();
console.log("context menu");
this.setState({
mouseX: e.clientX - 2,
mouseY: e.clientY - 4
});
}}>
And it should work.
Enjoy!
I ended up creating a popper context menu to replicate all the material-ui behavior for menus.
import React from "react";
import Popper from "#material-ui/core/Popper";
import Typography from "#material-ui/core/Typography";
import MenuList from "#material-ui/core/MenuList";
import MenuItem from "#material-ui/core/MenuItem";
import Paper from "#material-ui/core/Paper";
import { makeStyles } from "#material-ui/core/styles";
import { ClickAwayListener, Fade } from "#material-ui/core";
/* copied from https://github.com/mui-org/material-ui/blob/v4.3.2/packages/material-ui/src/Menu/Menu.js#L21 */
const useMenuStyles = makeStyles({
/* Styles applied to the `Paper` component. */
paper: {
// specZ: The maximum height of a simple menu should be one or more rows less than the view
// height. This ensures a tapable area outside of the simple menu with which to dismiss
// the menu.
maxHeight: "calc(100% - 96px)",
// Add iOS momentum scrolling.
WebkitOverflowScrolling: "touch"
},
/* Styles applied to the `List` component via `MenuList`. */
list: {
// We disable the focus ring for mouse, touch and keyboard users.
outline: 0
}
});
export default function FakedReferencePopper() {
const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState<null | any>(null);
const handleClose = () => {
setOpen(false);
};
const handleContextMenu = (e) => {
e.preventDefault();
const { clientX, clientY } = e;
setOpen(true);
const virtualElement = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: clientY,
right: clientX,
bottom: clientY,
left: clientX
})
};
setAnchorEl(virtualElement);
};
const id = open ? "faked-reference-popper" : undefined;
const menuClasses = useMenuStyles();
return (
<div>
<div onContextMenu={handleContextMenu}>
<Typography aria-describedby={id}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum
purus, bibendum sit amet vulputate eget, porta semper ligula. Donec
bibendum vulputate erat, ac fringilla mi finibus nec. Donec ac dolor
sed dolor porttitor blandit vel vel purus. Fusce vel malesuada ligula.
Nam quis vehicula ante, eu finibus est. Proin ullamcorper fermentum
orci, quis finibus massa. Nunc lobortis, massa ut rutrum ultrices,
metus metus finibus ex, sit amet facilisis neque enim sed neque.
Quisque accumsan metus vel maximus consequat. Suspendisse lacinia
tellus a libero volutpat maximus. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Nullam ipsum purus, bibendum sit amet
vulputate eget, porta semper ligula. Donec bibendum vulputate erat, ac
fringilla mi finibus nec. Donec ac dolor sed dolor porttitor blandit
vel vel purus. Fusce vel malesuada ligula. Nam quis vehicula ante, eu
finibus est. Proin ullamcorper fermentum orci, quis finibus massa.
Nunc lobortis, massa ut rutrum ultrices, metus metus finibus ex, sit
amet facilisis neque enim sed neque. Quisque accumsan metus vel
maximus consequat. Suspendisse lacinia tellus a libero volutpat
maximus. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nullam ipsum purus, bibendum sit amet vulputate eget, porta semper
ligula. Donec bibendum vulputate erat, ac fringilla mi finibus nec.
Donec ac dolor sed dolor porttitor blandit vel vel purus. Fusce vel
malesuada ligula. Nam quis vehicula ante, eu finibus est. Proin
ullamcorper fermentum orci, quis finibus massa. Nunc lobortis, massa
ut rutrum ultrices, metus metus finibus ex, sit amet facilisis neque
enim sed neque. Quisque accumsan metus vel maximus consequat.
Suspendisse lacinia tellus a libero volutpat maximus. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus,
bibendum sit amet vulputate eget, porta semper ligula. Donec bibendum
vulputate erat, ac fringilla mi finibus nec. Donec ac dolor sed dolor
porttitor blandit vel vel purus. Fusce vel malesuada ligula. Nam quis
vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis
finibus massa. Nunc lobortis, massa ut rutrum ultrices, metus metus
finibus ex, sit amet facilisis neque enim sed neque. Quisque accumsan
metus vel maximus consequat. Suspendisse lacinia tellus a libero
volutpat maximus. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nullam ipsum purus, bibendum sit amet vulputate eget, porta
semper ligula. Donec bibendum vulputate erat, ac fringilla mi finibus
nec. Donec ac dolor sed dolor porttitor blandit vel vel purus. Fusce
vel malesuada ligula. Nam quis vehicula ante, eu finibus est. Proin
ullamcorper fermentum orci, quis finibus massa. Nunc lobortis, massa
ut rutrum ultrices, metus metus finibus ex, sit amet facilisis neque
enim sed neque. Quisque accumsan metus vel maximus consequat.
Suspendisse lacinia tellus a libero volutpat maximus. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus,
bibendum sit amet vulputate eget, porta semper ligula. Donec bibendum
vulputate erat, ac fringilla mi finibus nec. Donec ac dolor sed dolor
porttitor blandit vel vel purus. Fusce vel malesuada ligula. Nam quis
vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis
finibus massa. Nunc lobortis, massa ut rutrum ultrices, metus metus
finibus ex, sit amet facilisis neque enim sed neque. Quisque accumsan
metus vel maximus consequat. Suspendisse lacinia tellus a libero
volutpat maximus.
</Typography>
</div>
<Popper
id={id}
open={open}
anchorEl={anchorEl}
transition
placement="bottom-start"
>
{({ TransitionProps }) => (
<ClickAwayListener onClickAway={handleClose}>
<Fade {...TransitionProps}>
<Paper className={menuClasses.paper}>
<MenuList className={menuClasses.list} autoFocus>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</Paper>
</Fade>
</ClickAwayListener>
)}
</Popper>
</div>
);
}
Here is codesandbox
https://codesandbox.io/s/popper-context-menu-t1u6r

React state change on mouse scroll

I have the following code to add to a variable every time the mouse has reached the end of the page :
const [number, setNum] = React.useState(5);
const addUp = () => {
setNum(number + 1);
}
const handleScroll = cb => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) cb();
};
React.useEffect(() => {
window.addEventListener("scroll", handleScroll(addUp));
}, [number]);
return (
<div className="App">
{console.log(number)}
sadly the code does not add to its existing value or with a little change to useEffect dependencies I end up in an infinite loop.
How can I add to my state by scrolling to the end of the page ?
the full code can be found at https://codesandbox.io/s/laughing-tree-pw6co
You can try something like the following. Don't add any dependencies for the useEffect() that creates the window event-listener. Anytime your component re-renders that will create a brand-new event listener on top of the one that already exists. You only want that useEffect() to execute once.
To assist you, you can add a second useState() to keep track of the scroll position. true if they are at the bottom, false otherwise. We'll call this endReached.
Then use a second useEffect() to verify the value of endReached, if true then increase number.
See working sandbox: http://codesandbox.io/s/youthful-hofstadter-h362t
App.js
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const myref = React.useRef(0);
const [number, setNum] = React.useState(5);
const [endReached, setEndReached] = React.useState(false);
const handleScroll = () => {
if (
window.scrollY + window.innerHeight >= document.body.offsetHeight &&
!endReached
) {
setEndReached(true);
} else {
setEndReached(false);
}
};
React.useEffect(() => {
if (endReached) {
setNum(number + 1);
}
}, [endReached]);
React.useEffect(() => {
window.addEventListener("scroll", () => handleScroll());
}, []);
return (
<div className="App">
<h1>number is {number}</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique
consequat imperdiet. Nulla vitae dolor in nisl fermentum egestas ut ac
nulla. Quisque aliquam libero sit amet neque ullamcorper molestie.
Phasellus massa ligula, rhoncus non consectetur sit amet, consequat eu
leo. Proin nec gravida sapien. Proin convallis malesuada est, nec
tincidunt massa. Quisque sit amet augue molestie, convallis purus quis,
porttitor quam. Duis iaculis ultrices ipsum a egestas. Duis pulvinar
urna sit amet egestas rutrum. Praesent sed consectetur felis. Nulla
massa libero, iaculis tempor porta ornare, hendrerit eu est. Praesent
tempor consequat nibh, in aliquam quam laoreet ut. Sed laoreet congue
urna id feugiat. Etiam egestas gravida dictum. Vestibulum nec sapien
turpis. In hac habitasse platea dictumst. Vestibulum odio turpis,
tincidunt sit amet ultricies at, interdum quis massa. Ut vestibulum quis
tortor viverra consequat. Phasellus ligula erat, efficitur non justo in,
pretium tempor nibh. Aliquam fringilla fermentum consectetur. Nunc
cursus convallis posuere. Pellentesque ac quam a mauris tempus dapibus
ut at quam. In vel tellus in eros elementum bibendum at mollis metus.
Fusce venenatis aliquet magna, non viverra odio dapibus vitae. Etiam
orci metus, consectetur ut enim at, tristique pellentesque augue. Sed eu
cursus metus. Maecenas imperdiet ultricies hendrerit. Maecenas porta
varius ipsum, a convallis magna pharetra ac. Sed sit amet dolor quis mi
luctus auctor. Mauris finibus, purus in dictum suscipit, nibh lacus
consequat orci, id ornare tellus lectus non urna. Nulla est neque,
sagittis at lacinia id, pulvinar quis sem. In hac habitasse platea
dictumst. Aenean vel porta ante, quis pulvinar velit. Etiam at mollis
sapien. Ut tristique pretium nisi, in tincidunt nisl pulvinar nec. Ut ac
ultricies erat, nec maximus neque. Vestibulum ante ipsum primis in
faucibus orci luctus et ultrices posuere cubilia Curae; Integer
vehicula, magna non aliquam sagittis, ex sapien interdum magna, vitae
gravida arcu nisi varius nunc. Nunc molestie ante a imperdiet finibus.
Aenean pellentesque rhoncus tincidunt. Suspendisse potenti. Nullam
dictum nibh vel sem ultrices, at lacinia sem cursus. Etiam dignissim
porta nulla a commodo. Nulla facilisi. Quisque non erat lectus.
Suspendisse a justo mi. Suspendisse ut sem et magna vulputate facilisis.
Morbi rutrum ornare tristique. Nam facilisis et urna ut fringilla. Etiam
pretium augue eu lorem mattis vestibulum. Nulla iaculis lorem ultricies
justo varius, id aliquet arcu fringilla. Nunc vehicula velit id nisi
imperdiet, ut lobortis arcu dignissim. Donec et orci iaculis, aliquet mi
quis, pellentesque elit. Aenean ipsum libero, molestie vitae libero eu,
mattis porta nulla. Duis vitae ornare turpis, eget lobortis enim. Cras
ut sagittis ipsum. Aenean luctus lacinia leo, a luctus augue pharetra
nec. Nulla blandit in est id cursus.
</p>
<button onClick={() => setNum(myref.current.value)}>Change</button>
<br />
<input ref={myref} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Justify text in React Native project for Android

I'm need justify a text and my code isn't work correctly.
import React from "react"
import { ScrollView, StyleSheet, View, WebView } from "react-native"
export default class App extends React.Component {
render() {
return (
<ScrollView style={styles.container}>
<WebView
source={{
html:
"<style>p{text-align:justify}</style>" +
"<p>" +
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus commodo tortor ut ipsum pharetra sodales. Praesent sed diam non lacus convallis dapibus. Sed vulputate erat risus, ac hendrerit eros egestas id. Etiam pellentesque auctor ipsum, non cursus nisi gravida sed. Ut eget pretium risus. Curabitur a lectus odio. Etiam felis urna, pharetra ut odio in, tristique suscipit tortor. Cras vitae risus odio. Etiam a leo elit. Duis molestie fermentum mi vitae pretium. Morbi luctus semper quam, et suscipit nisi convallis dictum. Fusce sit amet est dapibus, interdum ante non, lacinia metus. Donec at nulla non ante consectetur vulputate. Cras tristique porttitor ligula quis posuere. Integer nec laoreet felis, at tempor leo. Ut et convallis quam." +
"</p>"
}}
/>
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
margin: 20
}
})
The text isn't showed in the screen.
I'm try execute the code in a Android device.
Try removing the scrollView component, and putting the style in the Webview.
Here is an example:
https://snack.expo.io/SJQ5Mf9ym

Map Child within JSX Component Not Appearing

I'm trying to map an array that is the child of JSON objects found in the parent map. I'm still learning JSX and not sure if I can map within a JSX element, but it doesn't appear that my current solution is working because the object isn't rendering and there aren't errors appearing in my console that indicate any issue.
Here is the JSON Object:
[
{
"blogIdHash": "Zb2q97rX5n",
"title": "This is a test",
"discovery": "* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris bibendum porta felis, vel varius ligula venenatis eget.\r\n\r\n* Quisque placerat, arcu placerat tincidunt dapibus, justo sapien accumsan lorem, vitae vulputate orci eros sollicitudin nisi. Vivamus dignissim lectus id tincidunt viverra. \r\n\r\n* **Suspendisse ut tempor magna**, et mattis augue. Quisque pretium dui sollicitudin blandit maximus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, \r\n\r\nper inceptos himenaeos. Quisque mattis lacinia felis eget sagittis. Quisque sed eros scelerisque",
"created_at": "2017-09-01T11:46:31.914Z",
"updated_at": "2017-09-01T12:14:59.375Z",
"blog_comments": [
{
"blogIdHash": "Zb2q97rX5n",
"blogCommentId": 9,
"comment": "Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur porta, eros vitae laoreet pharetra, neque dolor facilisis augue, elementum maximus sapien tortor nec sem. Sed eget est sed felis tincidunt congue. Sed blandit neque vitae tellus interdum, non gravida tortor venenatis.",
"userId": 237,
"created_at": "2017-09-01T11:54:49.089Z",
"updated_at": "2017-09-01T11:54:49.089Z",
},
{
"blogIdHash": "Zb2q97rX5n",
"blogCommentId": 10,
"comment": "Sed laoreet felis ac interdum faucibus. Pellentesque non purus commodo, faucibus magna ac, pharetra urna. Sed sapien eros, efficitur in dui venenatis, euismod mattis nisl. Cras a posuere turpis. Morbi suscipit mollis risus, convallis auctor urna. Nam tristique, ex quis sodales tempor, massa urna maximus odio,",
"userId": 240,
"created_at": "2017-09-01T11:59:12.573Z",
"updated_at": "2017-09-01T11:59:12.573Z",
}
]
}
]
Here is the component setup (JSON blob is being set through a parent component. BlogFeed renders with first mapped object set in BlogCard):
const BlogFeed = props => {
return (
<div>
{
props.blogs.map((blog, index) => {
return (
<BlogCard {...blog} key={blog.blogIdHash}>
return(
{ blog.blog_comments.map((comment, i) => <Comments {...comment} key={i} />)}
)
</BlogCard>
);
})
}
</div>
)
}
const BlogCard = props => {
return (
<div key={props.blogIdHash}>
<h4>{props.title}</h4>
<p>{props.discovery}</p>
</div>
)
}
const Comments = props => {
return (
<div key={props.blogCommentId}>
<h4>{props.comment}</h4>
</div>
)
}
You need to specify in your BlogCard component where to render its children.
Like this:
const BlogCard = props => {
return (
<div>
<h4>{props.title}</h4>
<p>{props.discovery}</p>
{props.children} // its children
</div>
)
}
Also, you don't need the return inside the BlogCard component, map returns an array and that return will be pass in props.children along with the comments and show on your HTML as simple text.
You can check a working example here.
You can find more details about props.children here.

Resources