ReactJs的ScrollTo其实有坑

当我们想在React中点击某button滑动页面到另一个element的位置该怎么办呢?

首先第一个想到去stackOverflow查一下有没有类似的问题。

比如这个How to scroll to an element?

看看解答给的example。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ReadyToScroll extends Component {

constructor(props) {
super(props)
this.myRef = React.createRef()
}

render() {
return <div ref={this.myRef}></div>
}

scrollToMyRef = () => window.scrollTo(0, this.myRef.current.offsetTop)
// run this method to execute scrolling.

}

看上去好像没什么问题。当我们运用到自己的component中,突然就发现了问题。

ref.current.offsetTop 总是 undefined ?

当我们有自己的component。比如下面。

1
2
3
render() {
return <MyOwnComponent ref={this.myref}/>
}

我发现ref.current指向MyOwnComponent没错,但是offsetTop总是undefined。

原来,在react中,如果需要获取offsetTop,那这个ref必须放在html原生就有的virtualDom上。比如<div>之类。

好吧,那我现在这样应该可以了吧。

1
2
3
render() {
return <MyOwnComponent ><div ref={this.myref}></div></MyownComponent>
}

offsetTop总是0 ?

如下期待着我点击scroll to myref, 我能滑动到MyComponent,结果发现我总是滚动到页面顶部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ReadyToScroll extends Component {

constructor(props) {
super(props)
this.myRef = React.createRef()
}

render() {
return
<div>
<div style={height: 1000px;}></div>
<MyComponent ><div ref={this.myRef}></div></MyComponent>
<div style={height: 1000px;}></div>
<a onclick={scrollToMyRef}>scrollto myref</a>
</div>
}

scrollToMyRef = () => window.scrollTo(0, this.myRef.current.offsetTop)
// run this method to execute scrolling.

}

为啥呢? 原来offsetTop是该元素距离parent元素的offset。那么说来,这玩意儿紧贴着MyComponent自然offsetTop就是0了。

那该怎么办?

其实,使用this.myRef.current.ScrollIntoView()就行了。这样就不用我计算到底呀滑动多少距离,是相对哪儿的距离之类的。

反思

其实也不能说stackOverflow上的回答坑。提问的人是给了上下文的,回答的人自然按照提问的人给的code的上下文进行回答。

当我们实际运用到自己的code中的时候,因为不知道其中的一些细节,可能就是百般折腾了。

React的function Component中定义其他辅助函数时候的注意点

最近遇到一个不小的坑,具体来说就是当在function component中定义非render函数的时候, 常常因为忽略了arrow function的性质而导致错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const MyComponent = (props) => {
const myHandler = () => {
if(props.checked) {
dispatch(checkAction);
} else {
dispatch(uncheckAction);
}
}
return (
<>
<checkBox onClick={myHandler}>
....
</>
);
}

以上的例子中,实际运行时候发现,每次dispatch的都是相同的内容,如果前一次是check,那么总是check,刷新一下,如果前一次是uncheck,那么总是uncheck。这是为什么呢?

注意myhandler的本质是一个变量,整个变量代表一个函数。而整个函数使用了所谓的箭头函数,所以在定义整个变量的时候,其实里面的所有的东西就已经固定了,那就是整个MyComponent生成的时候,当时传递进来的props就成了myHandler里面固定的东西,
这个myHandler就算MyComponent重新render,也是不会改变的。

为啥不会改变? 因为MyComponent还是那个MyComponent,再被赋予不同的值调用一次而已,而本身myHandler的引用也没有改变。

具体,这个文章里面说得很详细。参考