I've got a React Component with several nested components. For page navigation I have a few buttons on the top.
The question is, how to scroll the page to the nested react component when a certain button is clicked, is it possible to do so without using jquery libs?
render() {
return (
<div>
<button onClick={(e) => { console.log('Scrolling to Item 1');}}>Button0</button>
<button onClick={(e) => { console.log('Scrolling to Item 2');}}>Button1</button>
<Layout>
<Item>
<Content>
...
</Content>
</Item>
<Item>
<Content>
...
</Content>
</Item>
</Layout>
}
</div>
);
}
Use scrollIntoView to scroll down to the element and React's refs to get the DOM of your component.
Here is a small example that illustrates what you want to do.
var Hello = React.createClass({
componentDidMount() {
alert("I will scroll now");
this.refs.hello.scrollIntoView(); // scroll...
},
render: function() {
return <div ref="hello">Hello {this.props.name}</div>; // reference your component
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
Have you tried using an anchor?
Put an id attribute ('myTarget') to your target component and replace the button with a link (href: '#mytarget').
This does not work with fixed headers, unfortunately.
Create a reference using useRef
const trackButton = useRef();
Use scrollIntoView method to scroll to the specific Element/ Component
trackButton.current.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" })
If you are using typescript.
import * as React from 'react';
class Hello extends React.Component<{}> {
private helloRef = React.createRef<HTMLDivElement>();
public render() {
return (
<div ref={this.helloRef}>Hello</div>
<button onClick={() => {
if (this.helloRef && this.helloRef.current) {
this.helloRef.current.scrollIntoView();
}
}
}>Button1</button>
);
}
}
Using React hooks and no 3rd party packages:
Create a reference using the React hook useRef
import { useRef } from 'react'
const firstItemRef = useRef(null);
Assign the reference to the component you want to scroll to
<Item ref={firstItemRef}>
Use the scrollIntoView method to scroll to the specific Element/Component
<button onClick={() => firstItemRef.current.scrollIntoView()}
Unless you need to implement it yourself, you can use react-scroll
Their demo is pretty much what you need.
you can use react-scroll
npm install react-scroll --save
and for information can go to this page
https://www.npmjs.com/package/react-scroll
Related
I am currently learning reactjs so I decided to build a react to-do list, am trying to toggle the display of a component but keep running into errors. Please what is the best way to toggle the display of the Action component when the user clicks on the icon with the class 'ri-menu-line'? This is my snippet.My Code snippet
I tried using react useRef to toggle between an empty string and a className and pass it as a prop to the Action component and then, in the Action component add the prop to the section classList but i keep running into huge errors.
Try doing this:
function App() {
const [show, setShow] = useState(false);
return (
<body>
<header>
<h1></h1>
<i onClick={() => setShow(!show)}></i>
<main>
{show && <Action />}
<Detail />
</main>
</header>
</body>
);
}
Toggle state to true/false.
Use && to display or hide component. see https://beta.reactjs.org/learn/conditional-rendering
import { useState } from "react";
export default function App() {
const [describeAppear, setDescribeAppear] = useState(false);
const onClick=()=>{
setDescribeAppear(!describeAppear)
}
return (
<div className="App">
<button onClick={onClick}>Toggle</button>
{describeAppear && <h2>Start editing to see some magic happen!</h2>}
</div>
);
}
I'm new to React and having some difficulty trying to add a new child component to a component that has already been rendered.
I have an App component which initially contains a Main component (main menu).
I also have Popover components which I want to appear on top of Main when they are children of <App> (and hence siblings of <Main>).
These Popover components vary in number. Each <Popover> can contain buttons which launch another <Popover> over the top again. So the structure would be like
<App>
<Main></Main>
<Popover></Popover>
<Popover></Popover>
...
</App>
However, when the page first loads there are no Popover components open, and the<App> is rendered without any. Here is a stripped-down version of my code:
class App extends React.Component{
constructor(props){ super(props) }
render(){
return (
<div>{this.props.children}</div>
)
}
}
class Main extends React.Component{
constructor(props){ super(props) }
render(){
return (
//main menu stuff here
)
}
}
ReactDOM.render(<App><Main /></App>, root);
How can I add new <Popover>s to my <App> when the user clicks something? Before React I would simply do App.appendChild(Popover) kind of thing, but I'm quite lost here.
I should add that the elements the user will click to trigger an initial <Popover> are not contained within <Main>; they are outside of the <App>, as I am trying to slowly transition my existing page to using React. I think this could be part of my problem.
So basically in React, you have multiple ways of doing this, but to be more reliable you need to have data that represents the dynamic components you will render in your DOM. And to do this you need to create a state and a function that can add new information to your state. Then simply by sharing this function with your other components, you can trigger it from wherever you want, and this will update your state which will increase the amount of dynamic components you will render.
Take a look at this example
import { useState } from "react";
export default function App() {
const [popups, setPopups] = useState([]);
const addNewPopup = () => {
setPopups([...popups, { title: "I am a popup" }]);
};
return (
<div className="App">
<ChildComponent onClick={addNewPopup} />
{popups.map((p) => {
return <Popup title={p.title} />;
})}
</div>
);
}
function ChildComponent({ onClick }) {
return (
<div>
<p>I am a child component</p>
<button onClick={onClick}>Add new element</button>
</div>
);
}
function Popup({ title }) {
return <div>I am a popup with title = {title}</div>;
}
Bit of a weird one here. My website is virtually done, there is just one issue. I've implemented tooltips, but they only display once I refresh the page! Here is a GIF reproducing the issue:
https://i.imgur.com/NbHyN77.mp4
The package is from NPM, at the following link: https://www.npmjs.com/package/react-tooltip
I've went through their documentation, troubleshooting and issues reported on their github repo, but there is nothing describing my issue. The site is live at: https://ezekias1337.github.io/Burning-Crusade-Talent-Calculator/#/
Oddly enough, if I bookmark one of the routes and load it in a fresh tab, it loads the first time. The issue only happens when I select the component from my Icons.
I made sure to import ReactTooltip from "react-tooltip"; I also added at the bottom of each component, and in app.js. Adding the data-for attribute hasn't fixed the issue.
Here is the code of my App.js:
import ReactTooltip from 'react-tooltip';
class App extends Component {
render() {
return (
<div className="App">
<CustomNavbar />
<ClassSelector />
<FooterComponent />
<ReactTooltip
html={true}
/>
</div>
);
}
}
export default App;
Here is the code relevant to tooltips in each individual component:
a.) The image that has the tooltip (every image has unique tooltip)
<img
onMouseEnter={this.displayMouseOverlayInnerElement}
onMouseLeave={this.hideMouseOverlayInnerElement}
onMouseDown={() => {
this.talentClick();
this.toolTipFunction();
}}
onTouchEnd={this.talentClick}
className="talentHover"
src={overlayImage}
style={{ display: "none" }}
data-tip={Hunter[0].toolTip[0]}
id="1"
/>
b.) The bottom of the component
<ReactTooltip data-html="true" />
Any idea what I can do to fix this?
In case anyone else is having this issue, I have finally found the solution after hours of pulling my hair out.
I used the following function:
rebuildToolTip(){
ReactTooltip.rebuild();
}
Subsequently I added this function as an event handler for onLoad on the component being rendered.
<div
style={{ position: "relative" }}
onContextMenu={(e) => e.preventDefault()}
className="frame-wrapper"
id="Hunter"
onLoad={() => {
this.scrollComponentIntoView();
this.rebuildToolTip();
}}
>
Here is something that worked for me (https://github.com/wwayne/react-tooltip/issues/268), create a new component for tool tip and pass required details in props as below code.
import React from "react";
import ReactDOM from "react-dom";
import ReactTooltip from "react-tooltip";
// Create root level element for react-tooltips
const domNode = document.createElement('div');
document.body.appendChild(domNode);
// Wrapper component to portal react-tooltips
function BodyPortal ({ children }) {
return ReactDOM.createPortal(
children,
domNode
);
}
// Custom tooltip wrapper to ensure all tooltips get rendered into the portal
function CustomReactTooltip (props) {
return (
<BodyPortal>
<ReactTooltip
type="light"
effect="solid"
delayHide={50}
{...props}
/>
</BodyPortal>
);
}
export default CustomReactTooltip;
I am building a table with fixed columns and my approach is to clone the table and place it on top position absolute, only showing the columns that are fixed.
I am using jQuery to clone, add class, and appending it to my DOM.
My table headers have a button and with cloning, I want the click listener to work on the clone.
Here is a link to jsfiddle for an example of the problem.
componentDidMount() {
jQuery('.button').clone(true).appendTo('#container')
}
render() {
return (
<div id="container">
<button
className="button"
onClick={() => alert('hi')}
>
say hi
</button>
</div>
)
}
Any ideas/solutions would be extremely helpful. If I can't go this route, I think I will have to create the same table again with a class for styling.
Thanks for the help!
Adding jQuery to a React project is not a good idea. jQuery is a direct DOM manipulator while React works from a Virtual DOM to intelligently update the DOM when necessary.
If you need to clone and you are using react, it's best to find a react way of doing it.
This should essentially do the same thing without jQuery (JSFiddle):
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
clone: ['first clone']
}
}
componentDidMount() {
this.setState({ clone: [...this.state.clone, 'new clone'] })
}
render() {
return (
<div id="container">
{ this.state.clone.map((v, i) =>
<button
key={i}
className="button"
onClick={() => alert('hi')}
>
say hi
</button>
)}
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector("#app"))
I'm trying to use this package react-ultimate-pagination: https://github.com/ultimate-pagination/react-ultimate-pagination
I want to set it up like their basic demo example: https://codepen.io/dmytroyarmak/pen/GZwKZJ
The usage instructions at the bottom of the github page say to import the component like this:
import ReactUltimatePagination from 'react-ultimate-pagination';
But the codepen demo just shows a constant:
const UltimatePagination = reactUltimatePaginationBasic.default;
I copied the code from the demo, but since it is mismatched with the import, I have an error of UltimatePagination being undefined and reactUltimatePaginationBasic undefined.
Does anyone know how to set up this component like the demo example?
The module exports the higher oder component createUltimatePagination as a named export. To import it using es6 import syntax it has to be the following:
import {createUltimatePagination} from 'react-ultimate-pagination';
Example App:
import React, { Component } from "react";
import { render } from "react-dom";
import { createUltimatePagination } from "react-ultimate-pagination";
const Button = ({ value, isActive, disabled, onClick }) => (
<button
style={isActive ? { fontWeight: "bold" } : null}
onClick={onClick}
disabled={disabled}
>
{value}
</button>
);
const PaginatedPage = createUltimatePagination({
itemTypeToComponent: {
PAGE: Button,
ELLIPSIS: () => <Button value="..." />,
FIRST_PAGE_LINK: () => <Button value="First" />,
PREVIOUS_PAGE_LINK: () => <Button value="Prev" />,
NEXT_PAGE_LINK: () => <Button value="Next" />,
LAST_PAGE_LINK: () => <Button value="Last" />
}
});
class App extends Component {
state = {
page: 1
};
render() {
return (
<PaginatedPage
totalPages={10}
currentPage={this.state.page}
onChange={page => this.setState({ page })}
/>
);
}
}
render(<App />, document.getElementById("root"));
Also see this working example on codesandbox.
To be honest I played around with the api of that library and actually it is unclear to me how this library is intended to be used. A pagination component should receive a list of items and then provide a render prop to render the current page with a slice of these items. It's a pagination that does not paginate. Basically it's only a button bar.
Just use var ReactUltimatePagination = require('react-ultimate-pagination'); after you've installed it with npm install react-ultimate-pagination --save