this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

More memoization

+197 -181
+197 -181
src/components/timeline.jsx
··· 1 + import { memo } from 'preact/compat'; 1 2 import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; 2 3 import { useHotkeys } from 'react-hotkeys-hook'; 3 4 import { InView } from 'react-intersection-observer'; ··· 243 244 ({ 244 245 scrollDirection, 245 246 nearReachStart, 246 - nearReachEnd, 247 + // nearReachEnd, 247 248 reachStart, 248 - reachEnd, 249 + // reachEnd, 249 250 }) => { 250 251 // setHiddenUI(scrollDirection === 'end' && !nearReachEnd); 251 252 if (headerRef.current) { ··· 516 517 ); 517 518 } 518 519 519 - function TimelineItem({ 520 - status, 521 - instance, 522 - useItemID, 523 - // allowFilters, 524 - filterContext, 525 - view, 526 - showFollowedTags, 527 - showReplyParent, 528 - }) { 529 - const { id: statusID, reblog, items, type, _pinned } = status; 530 - if (_pinned) useItemID = false; 531 - const actualStatusID = reblog?.id || statusID; 532 - const url = instance 533 - ? `/${instance}/s/${actualStatusID}` 534 - : `/s/${actualStatusID}`; 535 - let title = ''; 536 - if (type === 'boosts') { 537 - title = `${items.length} Boosts`; 538 - } else if (type === 'pinned') { 539 - title = 'Pinned posts'; 540 - } 541 - const isCarousel = type === 'boosts' || type === 'pinned'; 542 - if (items) { 543 - const fItems = filteredItems(items, filterContext); 544 - if (isCarousel) { 545 - // Here, we don't hide filtered posts, but we sort them last 546 - fItems.sort((a, b) => { 547 - // if (a._filtered && !b._filtered) { 548 - // return 1; 549 - // } 550 - // if (!a._filtered && b._filtered) { 551 - // return -1; 552 - // } 553 - const aFiltered = isFiltered(a.filtered, filterContext); 554 - const bFiltered = isFiltered(b.filtered, filterContext); 555 - if (aFiltered && !bFiltered) { 556 - return 1; 557 - } 558 - if (!aFiltered && bFiltered) { 559 - return -1; 560 - } 561 - return 0; 520 + const TimelineItem = memo( 521 + ({ 522 + status, 523 + instance, 524 + useItemID, 525 + // allowFilters, 526 + filterContext, 527 + view, 528 + showFollowedTags, 529 + showReplyParent, 530 + }) => { 531 + console.debug('RENDER TimelineItem', status.id); 532 + const { id: statusID, reblog, items, type, _pinned } = status; 533 + if (_pinned) useItemID = false; 534 + const actualStatusID = reblog?.id || statusID; 535 + const url = instance 536 + ? `/${instance}/s/${actualStatusID}` 537 + : `/s/${actualStatusID}`; 538 + let title = ''; 539 + if (type === 'boosts') { 540 + title = `${items.length} Boosts`; 541 + } else if (type === 'pinned') { 542 + title = 'Pinned posts'; 543 + } 544 + const isCarousel = type === 'boosts' || type === 'pinned'; 545 + if (items) { 546 + const fItems = filteredItems(items, filterContext); 547 + if (isCarousel) { 548 + // Here, we don't hide filtered posts, but we sort them last 549 + fItems.sort((a, b) => { 550 + // if (a._filtered && !b._filtered) { 551 + // return 1; 552 + // } 553 + // if (!a._filtered && b._filtered) { 554 + // return -1; 555 + // } 556 + const aFiltered = isFiltered(a.filtered, filterContext); 557 + const bFiltered = isFiltered(b.filtered, filterContext); 558 + if (aFiltered && !bFiltered) { 559 + return 1; 560 + } 561 + if (!aFiltered && bFiltered) { 562 + return -1; 563 + } 564 + return 0; 565 + }); 566 + return ( 567 + <li key={`timeline-${statusID}`} class="timeline-item-carousel"> 568 + <StatusCarousel title={title} class={`${type}-carousel`}> 569 + {fItems.map((item) => { 570 + const { id: statusID, reblog, _pinned } = item; 571 + const actualStatusID = reblog?.id || statusID; 572 + const url = instance 573 + ? `/${instance}/s/${actualStatusID}` 574 + : `/s/${actualStatusID}`; 575 + if (_pinned) useItemID = false; 576 + return ( 577 + <li key={statusID}> 578 + <Link 579 + class="status-carousel-link timeline-item-alt" 580 + to={url} 581 + > 582 + {useItemID ? ( 583 + <Status 584 + statusID={statusID} 585 + instance={instance} 586 + size="s" 587 + contentTextWeight 588 + enableCommentHint 589 + // allowFilters={allowFilters} 590 + /> 591 + ) : ( 592 + <Status 593 + status={item} 594 + instance={instance} 595 + size="s" 596 + contentTextWeight 597 + enableCommentHint 598 + // allowFilters={allowFilters} 599 + /> 600 + )} 601 + </Link> 602 + </li> 603 + ); 604 + })} 605 + </StatusCarousel> 606 + </li> 607 + ); 608 + } 609 + const manyItems = fItems.length > 3; 610 + return fItems.map((item, i) => { 611 + const { id: statusID, _differentAuthor } = item; 612 + const url = instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`; 613 + const isMiddle = i > 0 && i < fItems.length - 1; 614 + const isSpoiler = item.sensitive && !!item.spoilerText; 615 + const showCompact = 616 + (!_differentAuthor && isSpoiler && i > 0) || 617 + (manyItems && 618 + isMiddle && 619 + (type === 'thread' || 620 + (type === 'conversation' && 621 + !_differentAuthor && 622 + !fItems[i - 1]._differentAuthor && 623 + !fItems[i + 1]._differentAuthor))); 624 + const isStart = i === 0; 625 + const isEnd = i === fItems.length - 1; 626 + return ( 627 + <li 628 + key={`timeline-${statusID}`} 629 + class={`timeline-item-container timeline-item-container-type-${type} timeline-item-container-${ 630 + isStart ? 'start' : isEnd ? 'end' : 'middle' 631 + } ${_differentAuthor ? 'timeline-item-diff-author' : ''}`} 632 + > 633 + <Link class="status-link timeline-item" to={url}> 634 + {showCompact ? ( 635 + <TimelineStatusCompact status={item} instance={instance} /> 636 + ) : useItemID ? ( 637 + <Status 638 + statusID={statusID} 639 + instance={instance} 640 + enableCommentHint={isEnd} 641 + showFollowedTags={showFollowedTags} 642 + // allowFilters={allowFilters} 643 + /> 644 + ) : ( 645 + <Status 646 + status={item} 647 + instance={instance} 648 + enableCommentHint={isEnd} 649 + showFollowedTags={showFollowedTags} 650 + // allowFilters={allowFilters} 651 + /> 652 + )} 653 + </Link> 654 + </li> 655 + ); 562 656 }); 563 - return ( 564 - <li key={`timeline-${statusID}`} class="timeline-item-carousel"> 565 - <StatusCarousel title={title} class={`${type}-carousel`}> 566 - {fItems.map((item) => { 567 - const { id: statusID, reblog, _pinned } = item; 568 - const actualStatusID = reblog?.id || statusID; 569 - const url = instance 570 - ? `/${instance}/s/${actualStatusID}` 571 - : `/s/${actualStatusID}`; 572 - if (_pinned) useItemID = false; 573 - return ( 574 - <li key={statusID}> 575 - <Link class="status-carousel-link timeline-item-alt" to={url}> 576 - {useItemID ? ( 577 - <Status 578 - statusID={statusID} 579 - instance={instance} 580 - size="s" 581 - contentTextWeight 582 - enableCommentHint 583 - // allowFilters={allowFilters} 584 - /> 585 - ) : ( 586 - <Status 587 - status={item} 588 - instance={instance} 589 - size="s" 590 - contentTextWeight 591 - enableCommentHint 592 - // allowFilters={allowFilters} 593 - /> 594 - )} 595 - </Link> 596 - </li> 597 - ); 598 - })} 599 - </StatusCarousel> 600 - </li> 657 + } 658 + 659 + const itemKey = `timeline-${statusID + _pinned}`; 660 + 661 + if (view === 'media') { 662 + return useItemID ? ( 663 + <MediaPost 664 + class="timeline-item" 665 + parent="li" 666 + key={itemKey} 667 + statusID={statusID} 668 + instance={instance} 669 + // allowFilters={allowFilters} 670 + /> 671 + ) : ( 672 + <MediaPost 673 + class="timeline-item" 674 + parent="li" 675 + key={itemKey} 676 + status={status} 677 + instance={instance} 678 + // allowFilters={allowFilters} 679 + /> 601 680 ); 602 681 } 603 - const manyItems = fItems.length > 3; 604 - return fItems.map((item, i) => { 605 - const { id: statusID, _differentAuthor } = item; 606 - const url = instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`; 607 - const isMiddle = i > 0 && i < fItems.length - 1; 608 - const isSpoiler = item.sensitive && !!item.spoilerText; 609 - const showCompact = 610 - (!_differentAuthor && isSpoiler && i > 0) || 611 - (manyItems && 612 - isMiddle && 613 - (type === 'thread' || 614 - (type === 'conversation' && 615 - !_differentAuthor && 616 - !fItems[i - 1]._differentAuthor && 617 - !fItems[i + 1]._differentAuthor))); 618 - const isStart = i === 0; 619 - const isEnd = i === fItems.length - 1; 620 - return ( 621 - <li 622 - key={`timeline-${statusID}`} 623 - class={`timeline-item-container timeline-item-container-type-${type} timeline-item-container-${ 624 - isStart ? 'start' : isEnd ? 'end' : 'middle' 625 - } ${_differentAuthor ? 'timeline-item-diff-author' : ''}`} 626 - > 627 - <Link class="status-link timeline-item" to={url}> 628 - {showCompact ? ( 629 - <TimelineStatusCompact status={item} instance={instance} /> 630 - ) : useItemID ? ( 631 - <Status 632 - statusID={statusID} 633 - instance={instance} 634 - enableCommentHint={isEnd} 635 - showFollowedTags={showFollowedTags} 636 - // allowFilters={allowFilters} 637 - /> 638 - ) : ( 639 - <Status 640 - status={item} 641 - instance={instance} 642 - enableCommentHint={isEnd} 643 - showFollowedTags={showFollowedTags} 644 - // allowFilters={allowFilters} 645 - /> 646 - )} 647 - </Link> 648 - </li> 649 - ); 650 - }); 651 - } 652 682 653 - const itemKey = `timeline-${statusID + _pinned}`; 654 - 655 - if (view === 'media') { 656 - return useItemID ? ( 657 - <MediaPost 658 - class="timeline-item" 659 - parent="li" 660 - key={itemKey} 661 - statusID={statusID} 662 - instance={instance} 663 - // allowFilters={allowFilters} 664 - /> 665 - ) : ( 666 - <MediaPost 667 - class="timeline-item" 668 - parent="li" 669 - key={itemKey} 670 - status={status} 671 - instance={instance} 672 - // allowFilters={allowFilters} 673 - /> 683 + return ( 684 + <li key={itemKey}> 685 + <Link class="status-link timeline-item" to={url}> 686 + {useItemID ? ( 687 + <Status 688 + statusID={statusID} 689 + instance={instance} 690 + enableCommentHint 691 + showFollowedTags={showFollowedTags} 692 + showReplyParent={showReplyParent} 693 + // allowFilters={allowFilters} 694 + /> 695 + ) : ( 696 + <Status 697 + status={status} 698 + instance={instance} 699 + enableCommentHint 700 + showFollowedTags={showFollowedTags} 701 + showReplyParent={showReplyParent} 702 + // allowFilters={allowFilters} 703 + /> 704 + )} 705 + </Link> 706 + </li> 674 707 ); 675 - } 676 - 677 - return ( 678 - <li key={itemKey}> 679 - <Link class="status-link timeline-item" to={url}> 680 - {useItemID ? ( 681 - <Status 682 - statusID={statusID} 683 - instance={instance} 684 - enableCommentHint 685 - showFollowedTags={showFollowedTags} 686 - showReplyParent={showReplyParent} 687 - // allowFilters={allowFilters} 688 - /> 689 - ) : ( 690 - <Status 691 - status={status} 692 - instance={instance} 693 - enableCommentHint 694 - showFollowedTags={showFollowedTags} 695 - showReplyParent={showReplyParent} 696 - // allowFilters={allowFilters} 697 - /> 698 - )} 699 - </Link> 700 - </li> 701 - ); 702 - } 708 + }, 709 + (oldProps, newProps) => { 710 + const oldID = (oldProps.status?.id || '').toString(); 711 + const newID = (newProps.status?.id || '').toString(); 712 + return ( 713 + oldID === newID && 714 + oldProps.instance === newProps.instance && 715 + oldProps.view === newProps.view 716 + ); 717 + }, 718 + ); 703 719 704 720 function StatusCarousel({ title, class: className, children }) { 705 721 const carouselRef = useRef();