React scrollIntoView undefined - reactjs

On button click, I want scroll to component
class Host extends Component {
static contextType = HostContext;
constructor(props) {
super(props);
this.dateSelectorRef = React.createRef();
}
setStartDate () {
this.dateSelectorRef.current.setStartDate()
console.log('Not working', this.dateSelectorRef.current.scrollIntoView)
}
render() {
........
<DirectButton clickhandler={() => this.setStartDate()} />
........
........
<DateSelector
ref={this.dateSelectorRef}
onStartDateChange={this.onStartDateChange}
onEndDateChange={this.onEndDateChange}
/>
}
Above code, while I click on DirectButton event handler setStartDate call
but this.dateSelectorRef.current have no object scrollIntoView (undefined)
Any Idea what am I missing.

The DateSelector component does not implement this method, this is a DOM element method. You'll need to find a way to access the ref of the DOM element rendered by this component.

setStartDate = () => {
this.dateSelectorRef.current.setStartDate()
console.log('Not working', this.dateSelectorRef.current.scrollIntoView) }
This code will fix your issue

Related

ReactTS component class: how to save ref on the element

I use TypeScript and class component way and I need to save reference on my element. I am going to get the state of target element when 'resize' event will happen.
Accordingly How to use refs in React with Typescript I tried this:
export default class Carousel extends Component<CarouselProps, CarouselState> {
private ref: React.LegacyRef<HTMLDivElement>;
constructor(...) {
this.ref = React.createRef();
window.addEventListener('resize', (e) => this.resizeCarouselElements());
}
componentDidUpdate(...){...}
componentDidMount(...){...}
resizeCarouselElements = () => {
<...get current state of target element here ...>
}
render() {
return (
<div className='name' ref={this.ref}>
})
}
But after resizing the window I have got null:
How can I save reference on my div className='name' and use it after user's window resizing? Which way is the best practice? Store the ref in state, const or somewhere else?

How can I import element to another React component?

I've got 2 components and want to get Panel_Menu element in another child component to do some stuff with it.
class Panel extends Component {
constructor(props){
super(props);
this.menuRef = React.createRef();
}
componentDidMount() {
console.log (this.menuRef.current)
// works correctly
}
render() {
return(
<>
<Panel_Menu className="panel-menu" ref={this.menuRef}>
<Menu item={this.menuRef.current}/>
</Panel_Menu>
</>
)
}
}
class Menu extends Component {
constructor(props) {
super(props);
}
isSame = () => {
const isSlideClass = this.props.item;
console.log(isSlideClass)
// is null
// expected output: → <div class="panel-menu"></div>
}
render() {
return (
<Left_Menu >
<Panel_Menu_Items className="test" onClick={this.isSame} />
</Left_Menu>
);
}
}
How can I update data in done render() to reach my goal?
Or... how can I get element instantly in external Component (Menu in this case) to do some stuff with it?
Issue
The issue here is that React refs, when attached on the initial render, will be undefined during the initial render. This means that item={this.menuRef.current} will enclose the initial undefined ref value in the click handler of the child.
Solution
It's simple, you really just need to trigger a rerender to reenclose an updated React ref value. You can either add some state to the Panel component and update it in the componentDidMount lifecycle method, or just issue a forced update.
class Panel extends Component {
menuRef = createRef();
componentDidMount() {
console.log(this.menuRef.current);
this.forceUpdate(); // <-- trigger rerender manually
}
render() {
return (
<>
<PanelMenu className="panel-menu" ref={this.menuRef}>
<Menu item={this.menuRef.current} />
</PanelMenu>
</>
);
}
}
Demo

How do you use the Swiper callback methods in React?

I have a component class and need to be able to use .slideToLoop() and .update(), and haven't been able to figure out how to use those methods with the Swiper React library.
I need to do this when something else is clicked on, so that the Swiper can update (as it's hidden initially), and then slideTo the relevant slide.
At the moment, I have the click trigger in jQuery in componentDidMount() as I'm porting things over into React. But happy to change this as well if it's better to. The click happens on a grandchild component.
And I have the swiper instance being set into the state, but that happens after componentDidMount, so I can't access it from there.
Code:
constructor(props) {
super(props);
this.state = {
swiperIns: ''
}
}
setSwiper = (swiper) => {
this.setState({swiperIns: swiper}, () => {
console.log(this.state.swiperIns);
});
}
componentDidMount() {
const { appStore } = this.props;
if (!appStore.hasLoadedHomePage)
appStore.loadHomePage().catch((ex) => null);
const mySwiper = this.state.swiperIns;
console.log(mySwiper); // returns ''
$('.modal-trigger').on('click', function(e) {
e.preventDefault();
var modalToOpen = $(this).attr('data-modal-id');
console.log(modalToOpen);
if ($(this)[0].hasAttribute('data-slideindex')) {
const slideTo = parseInt($(this).attr('data-slideindex'));
// this.state.slideToLoop(slideTo);
}
$('#' + modalToOpen).show();
$('body').addClass('modal-open');
if ($('#' + modalToOpen).hasClass('modal--swiper')) {
// this.state.swiperIns.update();
}
});
}
and the return part of the Swiper:
<Swiper onSwiper={ this.setSwiper } spaceBetween={0} slidesPerView={1} loop>
...
</Swiper>
Any help or suggestions are appreciated.
Okay, so I figured it out.
First, you add a ref to the constructor:
constructor(props) {
super(props);
this.swiperRef = React.createRef();
}
And in componentDidMount, like so:
const mySwiper = this.swiperRef;
And then on the Swiper element, you set the ref to the Swiper instance like so:
<Swiper ref={ this.swiperRef }...</Swiper>
And then in button clicks/functions, you can use this.swiperRef.current?.swiper.slideNext(); or any other Swiper callback methods to update/slideTo/etc.

Scroll to element in an array after rendering using React ref callback

I would like to use ref callback to scroll to an element in an array after rendering.
Depending on state, it will scroll to different element based on this.state.scrollToId.
But I think the callback in the below code was not triggered before componentDidUpdate
P.S. Item is a customised component.
I have tried componentDidMount too.
Researches done:
Using 'ref' as array in React
https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
How to assign refs to multiple components
class A extends React.Component{
//...
state = { scrollToId: null}
scrollToMyRef = (myRef) =>{
window.scrollTo(0, myRef.current.offsetTop)
}
constructor(props) {
super(props)
this.itemRefs = {};
this.setItemRef = (element, id) => {
this.itemRefs[id] = element;
}
}
componentDidUpdate(){
if (this.state.scrollToId){
scrollToMyRef(this.itemRefs[this.state.scrollToId])
}
render(){
return (
<div>
{
this.state.aList.map((item)=>{
return (
<Item ref={(element) => {this. setItemRef(element, item.id)}}
</Item>
)
})
}
</div>)
}
}
Expected: based on the state, the page would scrolled to the corresponding element
Actual: itemRef[id] was undefined, and throw exception on scrollToMyRef

How to get the DOM node from a Class Component ref with the React.createRef() API

I have these two components:
import { findDOMNode } from 'react-dom';
class Items extends Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.selectedItemRef = React.createRef();
}
componentDidMount() {
if (this.props.selectedItem) {
this.scrollToItem();
}
}
componentWillReceiveProps(nextProps) {
if (this.props.selectedItem !== nextProps.selectedItem) {
this.scrollToItem();
}
}
scrollToItem() {
const itemsRef = this.ref.current;
const itemRef = findDOMNode(this.selectedItemRef.current);
// Do scroll stuff here
}
render() {
return (
<div ref={this.ref}>
{this.props.items.map((item, index) => {
const itemProps = {
onClick: () => this.props.setSelectedItem(item.id)
};
if (item.id === this.props.selectedItem) {
itemProps.ref = this.selectedItemRef;
}
return <Item {...itemProps} />;
})}
</div>
);
}
}
Items.propTypes = {
items: PropTypes.array,
selectedItem: PropTypes.number,
setSelectedItem: PropTypes.func
};
and
class Item extends Component {
render() {
return (
<div onClick={() => this.props.onClick()}>item</div>
);
}
}
Item.propTypes = {
onClick: PropTypes.func
};
What is the proper way to get the DOM node of this.selectedItemRef in Items::scrollToItem()?
The React docs discourage the use of findDOMNode(), but is there any other way? Should I create the ref in Item instead? If so, how do I access the ref in Items::componentDidMount()?
Thanks
I think what you want is current e.g. this.selectedItemRef.current
It's documented on an example on this page:
https://reactjs.org/docs/refs-and-the-dom.html
And just to be safe I also tried it out on a js fiddle and it works as expected! https://jsfiddle.net/n5u2wwjg/195724/
If you want to get the DOM node for a React Component I think the preferred way of dealing with this is to get the child component to do the heavy lifting. So if you want to call focus on an input inside a component, for example, you’d get the component to set up the ref and call the method on the component, eg
this.myComponentRef.focusInput()
and then the componentRef would have a method called focusInput that then calls focus on the input.
If you don't want to do this then you can hack around using findDOMNode and I suppose that's why it's discouraged!
(Edited because I realized after answering you already knew about current and wanted to know about react components. Super sorry about that!)

Resources