fix re-render previous nodes on state change

master
Hasan Genc 4 years ago
parent 4160d761a0
commit edbd72a679
  1. 5
      src/components/carousel/defaultProps.ts
  2. 90
      src/components/carousel/index.tsx
  3. 5
      src/helpers/index.ts
  4. 8
      src/hooks/index.ts
  5. 16
      src/styles/slider/styles.module.css.d.ts
  6. 34
      src/styles/styles.module.css.d.ts

@ -13,7 +13,6 @@ export const defaultProps: Required<CarouselProps> = {
useArrowKeys: false, useArrowKeys: false,
a11y: {}, a11y: {},
dynamic: false, dynamic: false,
beforeChange: null, paginationCallback: null,
afterChange: null, pageCount: 0,
extraItems: [],
}; };

@ -1,4 +1,10 @@
import React, { useState, FunctionComponent, KeyboardEvent, useEffect } from 'react'; import React, {
useState,
FunctionComponent,
KeyboardEvent,
useEffect,
useRef,
} from 'react';
import { Arrow } from '../arrow'; import { Arrow } from '../arrow';
import { ItemProvider } from '../item'; import { ItemProvider } from '../item';
import { import {
@ -13,6 +19,7 @@ import {
import { SlideDirection, Item, ArrowKeys } from '../../types/carousel'; import { SlideDirection, Item, ArrowKeys } from '../../types/carousel';
import { defaultProps } from './defaultProps'; import { defaultProps } from './defaultProps';
import styles from '../../styles/styles.module.css'; import styles from '../../styles/styles.module.css';
import { usePrevious } from '../../hooks';
export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselProps) => { export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselProps) => {
const props: Required<CarouselProps> = { ...defaultProps, ...userProps }; const props: Required<CarouselProps> = { ...defaultProps, ...userProps };
@ -29,40 +36,35 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
const [showArrow, setShowArrow] = useState( const [showArrow, setShowArrow] = useState(
getShowArrow(props.children.length, props.show, props.infinite, current), getShowArrow(props.children.length, props.show, props.infinite, current),
); );
const [dynamicElements, setDynamicElements] = useState<Item[]>(userProps.children); const prevChildren = usePrevious<Item[]>(userProps.children);
const [page, setPage] = useState<number>(0);
/*useEffect(() => { const itemsRef = useRef(initItems(props.children, props.slide, props.infinite));
if (Array.isArray(props.extraItems) && props.extraItems.length > 0) { const isPaginating = useRef(false);
const elements = dynamicElements.length > 0 ? dynamicElements : props.children;
setDynamicElements(elements.concat(props.extraItems));
}
}, [props.extraItems]);*/
useEffect(() => {
if (dynamicElements.length > props.children.length) {
slide(SlideDirection.Right, true);
}
}, [dynamicElements]);
if (props.dynamic) { if (props.dynamic) {
useEffect(() => { useEffect(() => {
console.log({
children: userProps.children,
dynamicElements,
});
const newItems = updateNodes( const newItems = updateNodes(
items, itemsRef.current,
dynamicElements, props.children,
prevChildren,
props.slide, props.slide,
props.infinite, props.infinite,
); );
console.log({ newItems });
setItems(newItems); setItems(newItems);
}, [userProps.children, dynamicElements]); itemsRef.current = newItems;
if (
page < props.pageCount &&
prevChildren &&
prevChildren?.length < props.children.length
) {
slide(SlideDirection.Right);
setPage(page + 1);
}
}, [props.children]);
} }
const slide = async (direction: SlideDirection, cb?: boolean) => { const slide = (direction: SlideDirection) => {
if ( if (
animation.isSliding || animation.isSliding ||
(direction === SlideDirection.Right && !showArrow.right) || (direction === SlideDirection.Right && !showArrow.right) ||
@ -71,19 +73,18 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
return; return;
} }
const dynamicElementsExists = dynamicElements.length > 0; if (
props.paginationCallback &&
if (!cb && props.beforeChange) { direction === SlideDirection.Right &&
const extraItems = await props.beforeChange(direction); page < props.pageCount - 1 &&
if (Array.isArray(extraItems) && extraItems.length > 0) { !isPaginating.current
const elements = ) {
dynamicElements.length > 0 ? dynamicElements : props.children; isPaginating.current = true;
setDynamicElements(elements.concat(extraItems)); props.paginationCallback(direction);
return; return;
}
} }
const elements = dynamicElementsExists ? dynamicElements : props.children; const elements = props.children;
const next = getCurrent(current, props.slide, elements.length, direction); const next = getCurrent(current, props.slide, elements.length, direction);
const rotated = props.infinite const rotated = props.infinite
@ -91,6 +92,7 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
: items; : items;
if (props.infinite && direction === SlideDirection.Right) { if (props.infinite && direction === SlideDirection.Right) {
setItems(rotated); setItems(rotated);
itemsRef.current = rotated;
} }
setAnimation({ setAnimation({
transform: transform:
@ -102,7 +104,13 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
setShowArrow(getShowArrow(elements.length, props.show, props.infinite, next)); setShowArrow(getShowArrow(elements.length, props.show, props.infinite, next));
setTimeout(() => { setTimeout(() => {
if (props.infinite) { if (props.infinite) {
setItems(cleanItems(rotated, props.slide, direction)); const cleanedItems = cleanItems(
direction === SlideDirection.Right ? itemsRef.current : rotated,
props.slide,
direction,
);
setItems(cleanedItems);
itemsRef.current = cleanedItems;
} }
setAnimation({ setAnimation({
transform: props.infinite transform: props.infinite
@ -113,6 +121,7 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
isSliding: false, isSliding: false,
}); });
}, props.transition * 1_0_0_0); }, props.transition * 1_0_0_0);
isPaginating.current = false;
}; };
const widthCallBack = (calculatedWidth: number) => { const widthCallBack = (calculatedWidth: number) => {
@ -164,7 +173,7 @@ export const Carousel: FunctionComponent<CarouselProps> = (userProps: CarouselPr
<ItemProvider <ItemProvider
{...props} {...props}
transition={animation.transition} transition={animation.transition}
items={items} items={itemsRef.current}
transform={animation.transform} transform={animation.transform}
slideCallback={slideCallback} slideCallback={slideCallback}
dragCallback={dragCallback} dragCallback={dragCallback}
@ -190,9 +199,8 @@ export interface CarouselProps {
useArrowKeys?: boolean; useArrowKeys?: boolean;
a11y?: { [key: string]: string }; a11y?: { [key: string]: string };
dynamic?: boolean; dynamic?: boolean;
beforeChange?: ((direction: SlideDirection) => Promise<any[] | null>) | null; paginationCallback?: ((direction: SlideDirection) => any) | null;
afterChange?: ((direction: SlideDirection) => void) | null; pageCount?: number;
extraItems?: any[];
} }
export interface CarouselState { export interface CarouselState {

@ -147,9 +147,14 @@ export function getOuterWidth(el: HTMLElement) {
export function updateNodes( export function updateNodes(
oldItems: Item[], oldItems: Item[],
newItems: Item[], newItems: Item[],
prevChildren: Item[] | undefined,
slide: number, slide: number,
infinite: boolean, infinite: boolean,
): Item[] { ): Item[] {
if (prevChildren && prevChildren.length < newItems.length) {
return initItems(newItems, slide, infinite);
}
const matchedItems = oldItems.map((oldItem) => { const matchedItems = oldItems.map((oldItem) => {
return newItems.find((newItem) => oldItem.key === newItem.key) as Item; return newItems.find((newItem) => oldItem.key === newItem.key) as Item;
}); });

@ -13,3 +13,11 @@ export const useWindowWidthChange = (callBack: (changed: number) => any) => {
}, []); }, []);
return; return;
}; };
export const usePrevious = <T>(value: T) => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
}

@ -1,10 +1,10 @@
export const sliderBase: string; export const sliderBase: string
export const slider: string; export const slider: string
export const sliding: string; export const sliding: string
interface Namespace { interface Namespace {
sliderBase: string; "sliderBase": string,
slider: string; "slider": string,
sliding: string; "sliding": string,
} }
declare const stylesModule: Namespace; declare const stylesModule: Namespace
export default stylesModule; export default stylesModule

@ -1,19 +1,19 @@
export const carouselBase: string; export const carouselBase: string
export const itemProvider: string; export const itemProvider: string
export const itemContainer: string; export const itemContainer: string
export const itemTracker: string; export const itemTracker: string
export const carouselArrow: string; export const carouselArrow: string
interface Namespace { interface Namespace {
carouselBase: string; "carouselBase": string,
'carousel-base': string; "carousel-base": string,
itemProvider: string; "itemProvider": string,
'item-provider': string; "item-provider": string,
itemContainer: string; "itemContainer": string,
'item-container': string; "item-container": string,
itemTracker: string; "itemTracker": string,
'item-tracker': string; "item-tracker": string,
carouselArrow: string; "carouselArrow": string,
'carousel-arrow': string; "carousel-arrow": string,
} }
declare const stylesModule: Namespace; declare const stylesModule: Namespace
export default stylesModule; export default stylesModule

Loading…
Cancel
Save