Reactjs React组件在重新渲染时滚动回顶部
我的React组件有这个问题,我无法解决。每次重新渲染时,它都会回滚到顶部。而且,我也不明白为什么它首先要重新渲染。基本上,我有祖父母、父母和孙子女。孙辈有一个单击事件,显示祖父母的另一个孩子(如果有意义的话)。该单击事件会执行一些操作,但它会导致祖父母的重新渲染,从而导致父组件滚动到顶部。我将加入我的代码,希望能澄清我在这里说的话。只是想提供一些背景 因此,主要问题是滚动到顶部。如果我们能够弄清楚它为什么要重新渲染并停止渲染,那将是一个额外的好处 祖父母(StaticLine.js): 如果需要更多信息或更多代码,请告诉我。如果您有任何见解,我们将不胜感激。Reactjs React组件在重新渲染时滚动回顶部,reactjs,Reactjs,我的React组件有这个问题,我无法解决。每次重新渲染时,它都会回滚到顶部。而且,我也不明白为什么它首先要重新渲染。基本上,我有祖父母、父母和孙子女。孙辈有一个单击事件,显示祖父母的另一个孩子(如果有意义的话)。该单击事件会执行一些操作,但它会导致祖父母的重新渲染,从而导致父组件滚动到顶部。我将加入我的代码,希望能澄清我在这里说的话。只是想提供一些背景 因此,主要问题是滚动到顶部。如果我们能够弄清楚它为什么要重新渲染并停止渲染,那将是一个额外的好处 祖父母(StaticLine.js): 如果需
const OrderColWithRef=React.forwardRef((props,ref)=>(
));
将其作为顶级功能移到静态行
之外
发生了什么事
React足够聪明,可以避免在只有部分Dom发生更改时重新创建html元素和装载内容。如果只有一个道具更改,它将保留该元素并仅更改其值等。这是通过比较元素来完成的。键入
有效的做法是在每个渲染上创建一个新的OrderColWithRef
函数,因为它是一个局部函数,所以类型不相等。每当StaticLine
中的任何内容发生更改时,React将卸载并重新装载一个新的html元素
永远不要嵌套组件声明。在函数中声明组件唯一有效的情况是HOC,即使这样,HOC函数本身也不是有效的元素,只是它的返回值是有效的
希望这能解决问题。您是否尝试过使用getSnapshotBeforeUpdate()
?据官方称:
在最近呈现的输出提交到DOM之前调用。它使您的组件能够在可能发生更改之前从DOM中捕获一些信息(例如滚动位置)
基本上,您可以在重新渲染之前访问当前的滚动位置,从getSnapshotBeforeUpdate()返回
在组件更新之后,使用可以访问从getSnapshotBeforeUpdate()
返回的值,并将滚动位置设置为重新渲染之前的位置。借用官方文件中的示例:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
类滚动列表扩展了React.Component{
建造师(道具){
超级(道具);
this.listRef=React.createRef();
}
getSnapshotBeforeUpdate(prevProps,prevState){
//我们是否在列表中添加新项目?
//捕获滚动位置,以便稍后调整滚动。
if(prevProps.list.length
我强烈建议使用软件包让您了解组件呈现的原因。我的问题是将接收新数据的东西作为组件处理,而不是作为返回组件的函数处理
将
更改为{newsList()}
成功了。您尝试过用React.memo包装组件吗?我没有,那是什么样子?它是做什么的?我把它添加到我的StaticLine组件的底部<代码>常量MemoizedStaticLine=React.memo(StaticLine);导出默认的MemoizedStaticLine代码>仍然滚动到顶部。@dmikester1您尝试过我的解决方案吗?你的问题解决了吗?我确实尝试了为什么你渲染插件,但在日志中没有看到任何有用的东西。由于我使用的是功能组件,我认为我不能使用getSnapshotBeforeUpdate()
,但我无权访问StaticLine之外的lineTitle、lineID或订单?为什么不将它们作为道具传递给OrderColWithRef
?
import React from 'react';
import PropTypes from 'prop-types';
import StaticOrder from '../order/StaticOrder';
import '../../scss/App.scss';
import { useGlobalSpinnerContext } from '../../context/GlobalSpinnerContext';
const StaticOrderColumn = (props) => {
const { title, lineID, orders } = props;
const isGlobalSpinnerOn = useGlobalSpinnerContext();
const sortedOrdersIDs = orders
.filter((o) => o.lineNum === lineID)
.sort((a, b) => a.linePosition - b.linePosition)
.map((o) => o.id);
return (
<div id={'line-0'} className={'col order-column'}>
<header className={'text-center title'}>
{title}{' '}
{sortedOrdersIDs.length > 0 && (
<span> ({sortedOrdersIDs.length})</span>
)}
</header>
<div className={'orders'}>
{orders &&
sortedOrdersIDs &&
sortedOrdersIDs.map((orderID, index) => {
const order = orders.find((o) => o.id === orderID);
return (
<StaticOrder
key={orderID}
order={order}
index={index}
/>
);
})}
{!sortedOrdersIDs.length && !isGlobalSpinnerOn && (
<h3>There are no orders on this line.</h3>
)}
</div>
</div>
);
};
StaticOrderColumn.propTypes = {
title: PropTypes.string.isRequired,
lineID: PropTypes.number.isRequired,
orders: PropTypes.array.isRequired,
ref: PropTypes.instanceOf(Element).isRequired
};
export default StaticOrderColumn;
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import '../../scss/App.scss';
import { getFormattedDate } from '../../utils/utils';
import { useGlobalActiveOrderActionsContext } from '../../context/GlobalActiveOrderContext';
import { useGlobalShowDetailsActionsContext } from '../../context/GlobalShowDetailsContext';
// import { stringTrunc } from '../../utils/utils';
const MyOrder = styled.div`
background-color: #193df4;
transition: background-color 1s ease;
`;
const devMode = true;
// const devMode = false;
const StaticOrder = (props) => {
const {
id,
item,
desc,
cust,
palletsOrd,
bagID,
chemicals,
totalBagsUsed,
linePosition,
palletsRem,
palletCount,
requestDate,
orderNumber,
comments
} = props.order;
const setActiveOrder = useGlobalActiveOrderActionsContext();
const setShowDetails = useGlobalShowDetailsActionsContext();
const orderID = id + '';
// show the details section when user clicks an order
// THIS IS WHERE THE ISSUE IS HAPPENING, WHEN THE ORDER IS CLICKED,
// THIS FUNCTION RUNS AND THE StaticLine COMPONENT RE-RENDERS AND THE StaticOrderColumn SCROLLS TO THE TOP
const showDetails = (orderID) => {
setActiveOrder(parseInt(orderID, 10));
setShowDetails(true);
};
return (
<MyOrder
id={orderNumber}
className={'order static'}
onClick={(e) => showDetails(orderID, e)}
>
{/*<div className={'orderID'}>{id}</div>*/}
<p className={'item-number'}>
{item !== '' ? `Item Number: ${item}` : ''}
</p>
<p>{desc !== '' ? `NPK: ${desc}` : ''}</p>
<p>{cust !== '' ? `Customer: ${cust}` : ''}</p>
<p>
{palletsOrd !== '' ? `Pallets Ordered: ${palletsOrd}` : ''}
</p>
<p>{bagID !== '' ? `Bag ID: ${bagID}` : ''}</p>
<p>{chemicals !== '' ? `Chemical : ${chemicals}` : ''}</p>
<p>
{requestDate !== ''
? `Request Date: ${getFormattedDate(new Date(requestDate))}`
: ''}
</p>
{devMode && (
<>
<div className={'id-line-num-pos'}>
<p>OrderID: {orderNumber}</p>
</div>
</>
)}
<div className={'total-bags'}>Total Bags: {totalBagsUsed}</div>
<div className={'pallets-remaining'}>
Pallets Left: {palletsRem}
</div>
<div className={'pallets-done'}>
Pallets Done: {palletCount}
</div>
<div className={'line-position'}>{linePosition + 1}</div>
{comments.length > 0 && (
// bunch of SVG code
)}
</MyOrder>
);
};
StaticOrder.propTypes = {
order: PropTypes.object,
id: PropTypes.number,
index: PropTypes.number,
title: PropTypes.string,
orderID: PropTypes.string
};
export default StaticOrder;
{orderType === 'completed' && showDetails && (
<OrderButtons
setLineID={setLineID}
setOrders={setOrders}
orders
lineNum={lineID}
/>
)}
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}