Context

我有一个组件,可以显示无限的帖子.我想检测第一个超过一天的元素,这样我就可以在该元素上方显示"昨天发布"的横幅(最终持续一周和一个月).

Buggy Solution

在呈现我的<李>但是,当我试图使用布尔状态标志来防止"昨天发布"附加到每一篇超过一天的帖子时,会出现一些奇怪的行为.

Code

无限滚动组件:

export function InfiniteFeed(props: InfiniteFeedProps) {
    const [page, setPage] = useState(0);
    const [shouldDisplay, setShouldDisplay] = useState(true)
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);
    const [posts, setPosts] = useState<Post[]>([])
    const [hasMore, setHasMore] = useState(false);

    const nowMillis = DateTime.local({zone: 'utc'}).toMillis();
    
    // have omitted dataFetching logic + ref observer logic

    const timeCheck = (eventTimeMillis: number) => {
        if (!shouldDisplay) {
            return false
        }
        if (!olderThanDay(eventTimeMillis, nowMillis)) {
            return false
        }
        setShouldDisplay(false) // setting this renders every time-check(post) to false
        return true
    }


    return (
        <div>
            <FeedWrapper>
                <Banner title="Infinite Feed"/>
                <ul style={{padding: 0}}>
                    {posts.map((post, i) => (
                        <FeedElement
                            key={post.id}
                            ref={(post.length === i + 1) ? lastEventElementRef : () => null}
                            id={post.id}
                            display={timeCheck(post.eventTimestamp)}  // if true, element prepends "posted yesterday"
                            // other props
                        />
                    ))}
                </ul>
            </FeedWrapper>
            <div></div>
        </div>
    );
}
Behavior

如果我不使用"shouldDisplay"状态做任何事情,提要会正确地在每一篇超过一天的帖子前面加上"Posted Dayed".但是,如果我将shouldDisplay设置为false(如代码中所示),timeCheck()总是false,并且"不会显示昨天发布的内容".

Ask

这里有什么问题吗?

推荐答案

我忽略了setState()会导致重新渲染,因此每次都会使timeCheck()返回false.为了获得时间分区提要所需的行为,我计算了在获取帖子时哪些索引应该预先设置时间字符串,然后如果元素索引在这个数组中,我将shouldDisplay()设置为true.这是我的密码

Solution
export function InfiniteFeed(props: InfiniteFeedProps) {
    const [page, setPage] = useState(0);
    const [shouldDisplay, setShouldDisplay] = useState(true)
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);
    const [posts, setPosts] = useState<Post[]>([])
    const [hasMore, setHasMore] = useState(false);

    const [timePartitions, setTimePartitions] = useState<number[]>([]) // indices of time buckets
    const now = DateTime.local({zone: 'utc'});
    // using luxon library for handling time and using
    // Duration api to account for the variable month lengths
    const timeBuckets = [
        now.minus(Duration.fromObject({month: 1})).toMillis(),
        now.minus(Duration.fromObject({week: 1})).toMillis(),
        now.minus(Duration.fromObject({day: 1})).toMillis()
    ];

    // have omitted useRef dom observer logic
    useEffect(() => {
        // ...
        CoreApi().post<GetEventsResponse>('posts', request)
            .then((res) => {
                const allPosts = [...posts, ...res.data.posts]
                setPosts(allPosts);
                calculateTimePartitions(allEvents)
                // ...
            })
    }, [page])

    const shouldDisplay = (index: number): boolean => {
        return timePartitions.find(num => num == index) != undefined
    }

    // calculate the indexes where we want to prepend time banner
    const calculateTimePartitions = (eventList: NewsEvent[]) => {
        let indexes = [];
        let intervals = timeBuckets
        for (let i = 0; i < posts.length; i++) {
            if (eventList[i].eventTimestamp < intervals[intervals.length - 1] ) {
                intervals.pop()
                indexes.push(i);
            }
        }
        setTimePartitions(indexes)
    }

    return (
        <div>
            <FeedWrapper>
                <Banner title="Infinite Feed"/>
                <ul style={{padding: 0}}>
                    {posts.map((post, i) => (
                        <FeedElement
                            key={post.id}
                            ref={(post.length === i + 1) ? lastEventElementRef : () => null}
                            id={post.id}
                            display={shouldDisplay(i)}  // if true, element prepends "posted yesterday"
                            // other props
                        />
                    ))}
                </ul>
            </FeedWrapper>
            <div></div>
        </div>
    );
}
Feed element logic
export const FeedElement = forwardRef<any, NewsEvent & FeedElementProps>((props: Post & FeedElementProps, ref) => {

    
    // can be more expensive
    const getTimeBucket = () => {
        const nowMillis = DateTime.local({zone: 'utc'})
        const eventTime = DateTime.fromMillis(props.eventTimestamp, {zone: 'utc'})
        const interval = Interval.fromDateTimes(eventTime, nowMillis)

        if (interval.length('day') > 1 && interval.length('day') < 2) {
            return 'Posted yesterday'
        }
        if (interval.length('day') > 2 && interval.length('week') < 1) {
            return 'Posted this week'
        }
        if (interval.length('week') > 1 && interval.length('month') < 1) {
            return 'Posted this month'
        }
        else if (interval.length('month') > 1) {
            return 'Posted over a month ago'
        }
        else {
            return '';
        }
    }

    return (
                <div>
                    {props.display ? (
                        <Banner title={getTimeBucket()} />
                    ) : (<></>)}
                    <div>
                        <li>
                        {/*other stuff*/}
                        </li>
                    </div>
                </div>

    )},
);

Reactjs相关问答推荐

如何在关闭和打开此 Select 输入时应用旋转效果?

如何在重新图表中更改悬停时的条形填充 colored颜色 ?

使用Reaction-Hook-Form时未激发React.js onBlur事件

需要特定的数学函数来标准化动画持续时间

如何使用useState响应快速/顺序状态更新

如何修复ReferenceError:在构建过程中未定义导航器

使用以Jest 的方式返回 Promise 的方法来模拟可构造的 API 类时出现问题

PWA:注册事件侦听器不会被触发

如何在react 中过滤数组的数组?

无法读取未定义的属性(阅读 'editQuoteModalShown')reactredux

React JS:如何判断用户使用的是浏览器 url 还是桌面 electron

map 未显示在react 传单中

使用 react-router-dom 时弹出空白页面

不能在我的代码中使用 .给我一个警告!有人知道解决方案吗?

如何在props 更改时运行自定义挂钩?

Storybook - 无法解析generated-stories-entry.cjs/字段browser不包含有效的别名配置

运行开发服务器时如何为 Vite 指定运行时目录

如何在组件文件夹内的react 组件文件中导入外部css文件?

Map 函数只返回 Array 中的图像

react-three-fiber 场景背景比原图更亮