我已经为我的组件之一实现了无限滚动。代码结构看起来像这样
我有一个名为的父组件,该组件对文章List进行访存。下面是代码
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Row from 'muicss/lib/react/row'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
// actions
import { fetchArticles } from '../../../actions/KmActions'
import { setAppHeader } from "../../../actions";
// components
// import KmSubNav from './kmSubNav'
import ArticleList from './articleList'
import Spinner from '../../../components/Reusable/Spinner'
import AuthorsModal from './modal'
const ReactGA = require("react-ga");
ReactGA.initialize("UA-119424435-1");
//prod settings
// ReactGA.initialize("UA-119458679-1");
class KnowledgeMain extends Component {
constructor(props) {
super(props)
this.state = {
kmLink: ''
}
}
static propTypes = {
userProfile: PropTypes.object.isRequired,
setAppHeader: PropTypes.func.isRequired,
fetchArticles: PropTypes.func.isRequired
}
componentDidMount() {
const { setAppHeader, userProfile, fetchArticles } = this.props
const { articleTabType } = this.state
setAppHeader('Knowledge')
const kmLink = this.props.userProfile.getIn(['homePage', 'links', 'km-service-link'])
ReactGA.set({
checkProtocolTask: null,
checkStorageTask: null,
userId: this.props.userProfile.getIn(['details', 'id'])
});
ReactGA.pageview('Knowledge Management');
// End Analytics
if (kmLink) {
this.setState({ kmLink })
fetchArticles(`${kmLink}v3/${articleTabType}`)
}
}
componentDidUpdate(prevProps) {
const { userProfile, fetchArticles } = this.props
const { userProfile: prevUserProfile } = prevProps
const toJSUserProfile = userProfile ? userProfile.toJS() : null
const toJSPrevUserProfile = userProfile ? prevUserProfile.toJS() : null
if (toJSUserProfile) {
const prevBaseurl = toJSPrevUserProfile.homePage.links ? toJSPrevUserProfile.homePage.links['km-service-link'] : null
const baseurl = toJSUserProfile.homePage.links ? toJSUserProfile.homePage.links['km-service-link'] : null
const { articleTabType } = this.state
if (baseurl && baseurl !== prevBaseurl) {
this.setState({ kmLink: baseurl })
fetchArticles(`${baseurl}v3/${articleTabType}`)
}
}
}
render() {
const { artieclesLoading } = this.props
if (artieclesLoading) return <Spinner />
return (
<ReactCSSTransitionGroup
transitionName="phub"
transitionEnterTimeout={2000}
transitionLeaveTimeout={2000}
transitionAppear={true}
transitionAppearTimeout={500}
>
<div className="container">
<ArticleList
/>
</div>
</ReactCSSTransitionGroup>
)
}
}
const mapStateToProps = state => ({
userProfile: state.get('userProfile'),
artieclesLoading: state.get('km').get('articlesLoading')
})
const mapDispatchToProps = dispatch => {
let storage = window.localStorage
return {
setAppHeader: header => dispatch(setAppHeader(header)),
fetchArticles: url => dispatch(fetchArticles({ storage, url }))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(KnowledgeMain)
在我的子组件中,我正在使用来自父组件的访存结果。以下是显示使用“ react-infinite-scroller”实现无限滚动的列表的子组件
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Row from 'muicss/lib/react/row'
import { hashHistory } from 'react-router'
import InfiniteScroll from "react-infinite-scroller"
import ReactLoading from "react-loading"
import { blue800 } from "material-ui/styles/colors"
// actions
import { updateArticle, readLaterArticle, fetchArticles } from '../../../actions/KmActions'
// components
import ArticleCard from './ArticleCard'
// helpers
import { parseUrl } from '../../../utilities/helpers'
class ArticleListComponent extends Component {
constructor(props) {
super(props)
this.titleClick = this.titleClick.bind(this)
}
static propTypes = {
articles: PropTypes.object.isRequired,
pagination: PropTypes.object.isRequired
}
titleClick(e, article) {
const link_type = article.get('attributes').get('link_type')
const id = article.get('id')
const source_url = article.get('attributes').get('source_url')
const detail = article.get('links').get('detail')
if (link_type === 'External') {
e.preventDefault();
window.open(source_url, "_blank", "hidden=no")
// window.open(source_url, "_blank")
e.preventDefault();
}
if (link_type === 'Internal') {
hashHistory.push({
pathname: `/km/article/${id}`
})
}
}
render() {
const { articles, pagination, loadMore, articlesLoading, onShowMoreClick } = this.props
return (
<InfiniteScroll
pageStart={0}
initialLoad={false}
loadMore={e => {
if (articlesLoading) return
loadMore(pagination.get("next"))
}}
hasMore={pagination.get("next")}
loader={
<div style={{ display: "flex", justifyContent: "center" }}>
<ReactLoading type="bubbles" color={blue800} height={50} width={50} />
</div>
}
>
<div className="container">
<div className="o-page-wrapper-km">
<Row>
{
articles && articles.size === 0
? (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<h2>No Articles to Show as of now</h2>
</div>
)
: (
<div>
{
articles.map((article, index) => (
<ArticleCard
key={index}
article={article}
titleClick={this.titleClick}
tags={article.get('attributes').get('taxonomy_list').split(',')}
mediaType={parseUrl(article.get('attributes').get('media_url'))}
handleLikeClick={this.props.likeArticle}
handleDislikeClick={this.props.dislikeArticle}
handleReadLaterClick={this.props.readLaterArticle}
handleUndoReadLaterClick={this.props.undoReadLaterArticle}
onShowMoreClick={onShowMoreClick}
/>
))
}
</div>
)
}
</Row>
</div>
</div>
</InfiniteScroll>
)
}
}
const mapStateToProps = state => ({
articles: state.get('km').get('articles'),
pagination: state.get('km').get('pagination'),
articlesLoading: state.get('km').get('articlesLoading')
})
const mapDispatchToProps = dispatch => {
let storage = window.localStorage
return {
likeArticle: link => dispatch(updateArticle({ storage, link, method: 'POST', type: 'like' })),
dislikeArticle: link => dispatch(updateArticle({ storage, link, method: 'DELETE', type: 'dislike' })),
readLaterArticle: link => dispatch(readLaterArticle({ storage, link, method: 'POST', type: 'read_later' })),
undoReadLaterArticle: link => dispatch(readLaterArticle({ storage, link, method: 'DELETE', type: 'undo_read_later' })),
loadMore: url => dispatch(fetchArticles({ storage, url, type: 'update' }))
}
}
const ArticleList = connect(mapStateToProps, mapDispatchToProps)(ArticleListComponent)
export default ArticleList
以下也是我用来更新我的redux商店的reducer
这是在第一个提取调用中设置文章列表
case Actions.KNOW_ARTICLES_RES:
const articles = action.articles || []
newState = state
.set('articlesLoading', false)
.set('articles', fromJS(articles))
.set('pagination', fromJS(action.pagination))
return newState
这用于使用无限滚动的loadMore动作中接收的新数据更新文章列表
case Actions.KNOW_UPDATE_ARTICLES_RES: {
const articles = action.articles || []
const loadedArticles = state.hasIn([
"articles"
])
? state.get("articles")
: List()
newState = state
.set('articlesLoading', false)
.set('articles', loadedArticles.concat(fromJS(articles)))
.set('pagination', fromJS(action.pagination))
return newState
}
所以这是我面临的问题,因为我在InfiniteScroll组件的loadMore操作上的子组件中执行提取调用后,父组件也会重新渲染,因为整个列表都会重新渲染,它似乎不是滚动动作,而是每次都刷新页面。我在这里丢失的是父组件正在重新渲染?
答案 0 :(得分:0)
很抱歉,但是我意识到我在这里做错了,我在子组件和父组件中都使用了相同的加载状态,并且每次执行fetch调用时我都在重新初始化加载状态,因此父组件正在重新渲染,因为在子组件中,InfiniteScroll调用加载了more函数,该函数会重新初始化articleLoading,我也在父组件中使用它来显示Spinner,因此,当其prop更改时,父组件会重新渲染。