reactjs - 用户向下滚动时获取更多内容
问题描述
我有一个带有搜索输入的页面,一旦用户点击提交结果就会出现。
可能有很多结果,我不想一次全部加载,如何在鼠标移动时使用 Lodash 油门将更多数据获取到页面中?
这是我的反应组件:
const getContacts = async (searchString) => {
const { data: contactsInfo} = await axios.get(`api/Contats/Search?contactNum=${searchString}`);
return contactsInfo;
};
export default class Home extends React.Component {
state = {
contactsInfo: [],
searchString: '',
};
handleSubmit = async () => {
const { searchString } = this.state;
const contactsInfo = await getContacts(searchString);
this.setState({ contactsInfo });
};
onInputChange = e => {
this.setState({
searchString: e.target.value,
});
};
onMouseMove = e => {
};
render() {
const { contactsInfo, searchString, } = this.state;
return (
<div css={bodyWrap} onMouseMove={e => this.onMouseMove(e)}>
<Header appName="VERIFY" user={user} />
{user.viewApp && (
<div css={innerWrap}>
<SearchInput
searchIcon
value={searchString || ''}
onChange={e => this.onInputChange(e)}
handleSubmit={this.handleSubmit}
/>
{contactsInfo.map(info => (
<SearchResultPanel
info={info}
isAdmin={user.isAdmin}
key={info.id}
/>
))}
</div>
)}
<Footer />
</div>
);
}
}
解决方案
我想,使用getContacts()
您检索所有联系人,然后您只想以某种速度显示它们,例如显示前 20 个,然后当您到达最后一个时,又会出现 20 个。只是问,因为这与“让我们获取前 20 个联系人,显示他们,然后当用户到达最后一个,再获取 20 个联系人”确实不同。
所以,如果我的第一个假设是正确的,我可以推荐你使用Intersection Observer API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
这在像您这样的情况下非常有用(它甚至写在文档“在滚动页面时延迟加载图像或其他内容。”)。
这个想法是你应该添加这个 Intersection Observer,并开始对最后一张图像进行观察:这个观察者将在最后一张图像出现在屏幕上时运行回调(你甚至可以决定必须打开的图像的百分比屏幕)。例如,您可以说,屏幕上一出现 1px 的图像,您就添加了另外 20s 的图像!
请注意,一旦显示另外 20 秒的图像,您必须不观察当前观察到的图像,并观察新的最后一个图像!
我也可以建议不要将观察者放在最后一张图像上,但可能放在倒数第三张上。
编辑:我不确定这是否能回答您的问题。如果我考虑标题“在用户向下滚动时获取更多内容”,它会这样做,但它实际上并没有使用鼠标悬停(尽管我认为这个实现是你目标的最佳实现)。
EDIT2:就这样,我添加了小提琴,这里有codepen:https ://codepen.io/Gesma94/pen/OqpOQb
请注意,我已经用不同颜色的 div 模拟了联系人。实际情况是,当屏幕上出现倒数第三个联系人 (div) 时,状态中会添加新联系人。现在联系人只是空对象,但你可以在里面运行 fetch 或做任何你想做的事情fetchMoreContent()
。这足够清楚吗?:) 我也评论了代码。
/* Just a function that create a random hex color. */
function randomColor() {
let randomColor = '#';
const letters = '0123456789ABCDEF';
for (let i = 0; i < 6; i++) {
randomColor += letters[Math.floor(Math.random() * 16)];
}
return randomColor;
}
class Home extends React.Component {
contactList = null; // Ref to the div containing the contacts.
contactObserved = null; // The contact which is observed.
intersectionObserver = null; // The intersectionObserver object.
constructor(props) {
super(props);
this.contactList = React.createRef();
this.state = {
loading: true,
contactsToShow: 0,
contacts: []
};
}
componentDidMount() {
/* Perform fetch here. I'm faking a fetch using setTimeout(). */
setTimeout(() => {
const contacts = [];
for (let i=0; i<100; i++) contacts.push({});
this.setState({loading: false, contacts, contactsToShow: 10})}, 1500);
}
componentDidUpdate() {
if (!this.state.loading) this.handleMoreContent();
}
render() {
if (this.state.loading) {
return <p>Loading..</p>
}
return (
<div ref={this.contactList}>
{this.state.contacts.map((contact, index) => {
if (index < this.state.contactsToShow) {
const color = contact.color || randomColor();
contact.color = color;
return (
<div
className="contact"
style={{background: color}}>
{color}
</div>
);
}
})}
</div>
);
}
handleMoreContent = () => {
/* The third last contact is retrieved. */
const contactsDOM = this.contactList.current.getElementsByClassName("contact");
const thirdLastContact = contactsDOM[contactsDOM.length - 3];
/* If the current third last contact is different from the current observed one,
* then the observation target must change. */
if (thirdLastContact !== this.contactObserved) {
/* In case there was a contact observed, we unobserve it and we disconnect the
* intersection observer. */
if (this.intersectionObserver && this.contactObserved) {
this.intersectionObserver.unobserve(this.contactObserved);
this.intersectionObserver.disconnect();
}
/* We create a new intersection observer and we start observating the new third
* last contact. */
this.intersectionObserver = new IntersectionObserver(this.loadMoreContent, {
root: null,
threshold: 0
});
this.intersectionObserver.observe(thirdLastContact);
this.contactObserved = thirdLastContact;
}
}
loadMoreContent = (entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
let contactsCounter = this.state.contacts.length;
let contactsToShow = this.state.contactsToShow + 10;
if (contactsToShow > contactsToShow) contactsToShow = contactsToShow;
this.setState({contactsToShow});
}
})
}
}
ReactDOM.render(<Home />, document.getElementById('root'));
@import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
.contact {
width: 200px;
height: 100px;
border: 1px solid rgba(0,0,0,0.1);
}
.contact + .contact {
margin-top: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id='root'></div>
推荐阅读
- javascript - Angular将字典传递给更改事件
- vb.net - 如何让图片框随机出现在屏幕上
- ios - IOS 14 XCode Beta 4 中的 UISwitch 行为发生了变化
- java - 如何在多个活动中实现夜间模式的保存?
- python - Scrapy:网页下一个按钮使用 WebForm_DoPostBackWithOptions()
- arrays - 如何将修改后的数组与原始数组(在 Lua 中)进行比较?
- javascript - 我试图在 JavaScript 中找到一个多态性的例子——OOP 的 4 个支柱之一。这是一个吗?
- python - python用额外的时间值更新纪元值
- python - 为什么这是错误的(排列)?
- android - Android:从“最近”选项卡打开应用程序时,共享 ACTION_SEND 的数据会保留