我使用此代码作为参考来构建名称https://gist.github.com/estaub/91e54880d77a9d6574b829cb0d3ba021的可滑动列表
该代码成为JSX组件。然后,我有一个包含两个列表的父组件,其想法是在滑动时将其中一个列表中的项目移到第二个列表中。
代码工作正常,当我实现列表时问题就开始了。当我滑动一个Item时,父组件会触发一个函数,该函数获取滑动的Item,从第一个中删除并添加到第二个列表中。父组件再次被渲染。 问题在于,该条目下的被删除的条目似乎正在接收为使条目消失而添加的类。换句话说,就像我要擦除两个项目一样。删除的项目已从列表中删除,但其下面的项目现在仍具有DOM的隐藏属性,因此我们再也看不到它。
出于某种原因,useRef似乎是在选择刚刚删除的元素下方的元素,然后将其应用样式。
有什么想法我可以尝试解决吗?
这是我的可滑动组件
import React, {
useEffect, useRef,
} from 'react';
interface IOwnProps {
onSwipe?: () => void;
}
const SwipeableListItem:React.FC<IOwnProps> = ({
children, onSwipe,
}) => {
const listElementRef = useRef<HTMLDivElement | null>(null);
const wrapperRef = useRef<HTMLDivElement | null>(null);
const backgroundRef = useRef<HTMLDivElement | null>(null);
const dragStartXRef = useRef(0);
const leftRef = useRef(0);
const draggedRef = useRef(false);
useEffect(() => {
const onSwiped = () => {
if (onSwipe) {
onSwipe();
}
};
const onDragEnd = () => {
if (draggedRef.current) {
draggedRef.current = false;
const threshold = 0.3;
let elementOffsetWidth = 0;
if (listElementRef.current) {
elementOffsetWidth = listElementRef.current.offsetWidth;
}
if (leftRef.current < elementOffsetWidth * threshold * -1) {
leftRef.current = (-elementOffsetWidth * 2);
if (wrapperRef.current) {
wrapperRef.current.style.maxHeight = (0).toFixed(1);
}
onSwiped();
} else {
leftRef.current = 0;
}
if (listElementRef.current) {
listElementRef.current.className = 'BouncingListItem';
listElementRef.current.style.transform = `translateX(${leftRef.current}px)`;
}
}
};
const onDragEndMouse = (ev: MouseEvent) => {
window.removeEventListener('mousemove', onMouseMove);
onDragEnd();
};
const onDragEndTouch = (ev: TouchEvent) => {
window.removeEventListener('touchmove', onTouchMove);
onDragEnd();
};
window.addEventListener('mouseup', onDragEndMouse);
window.addEventListener('touchend', onDragEndTouch);
return () => {
window.removeEventListener('mouseup', onDragEndMouse);
window.removeEventListener('touchend', onDragEndTouch);
};
}, [onSwipe]);
const onDragStartMouse = (ev: React.MouseEvent) => {
onDragStart(ev.clientX);
window.addEventListener('mousemove', onMouseMove);
};
const onDragStartTouch = (ev: React.TouchEvent) => {
const touch = ev.targetTouches[0];
onDragStart(touch.clientX);
window.addEventListener('touchmove', onTouchMove);
};
const onDragStart = (clientX: number) => {
draggedRef.current = true;
dragStartXRef.current = clientX;
if (listElementRef.current) {
listElementRef.current.className = 'ListItem';
}
requestAnimationFrame(updatePosition);
};
const updatePosition = () => {
if (draggedRef.current) {
requestAnimationFrame(updatePosition);
}
if (listElementRef.current) {
listElementRef.current.style.transform = `translateX(${leftRef.current}px)`;
}
// fade effect
const opacity = (Math.abs(leftRef.current) / 100);
if (opacity < 1 && opacity.toString() !== backgroundRef.current?.style.opacity) {
if (backgroundRef.current) {
backgroundRef.current.style.opacity = opacity.toString();
}
}
};
const onMouseMove = (ev: MouseEvent) => {
const left = ev.clientX - dragStartXRef.current;
if (left < 0) {
leftRef.current = left;
}
};
const onTouchMove = (ev: TouchEvent) => {
const touch = ev.targetTouches[0];
const left = touch.clientX - dragStartXRef.current;
if (left < 0) {
leftRef.current = left;
}
};
return (
<div className="Wrapper" ref={wrapperRef}>
<div className="Background" ref={backgroundRef}>
<span>Remove</span>
</div>
<div
className="ListItem"
ref={listElementRef}
onMouseDown={onDragStartMouse}
onTouchStart={onDragStartTouch}
role="presentation"
>
{children}
</div>
</div>
);
};
export default SwipeableListItem;
这是父组件,我在其中处理列表
import React, {
useEffect, useState,
} from 'react';
import SwipeableListItem from './SwipeableListItem';
interface ITest{
id:number;
}
interface IOwnProps{
list1?: ITest[];
list2?: ITest[];
}
const MyList: React.FC<IOwnProps> = ({
list1, list2,
}) => {
const [displayList1, setDisplayList1] = useState<boolean>(true);
const [list, setList] = useState<Array<Array<ITest>>>([[], []]);
useEffect(() => {
setList([list1 || [], list2 || []]);
}, [list1, list2]);
const handleSwitchList = () => {
setDisplayList1(!displayList1);
};
//without this function it works, but the item does not get removed from the list
const handleSendToSecondList = (id: number, myList1: ITest[], myList2: ITest[]) => {
const foundItem = myList2.find((s) => s.id === id);
const newList1 = myList1;
if (foundItem) {
// push item to list 1
newList1.push(foundItem);
// remove list 2
const newList2 = myList2.filter((s) => s.id !== foundItem.id);
setList([newList1, newList2]);
}
};
return (
<div>
<div>
<button
type="button"
className={`btn ${displayList1 ? 'btn-primary' : ''}`}
onClick={handleSwitchList}
>
List 1
</button>
<button
type="button"
className={`btn ${!displayList1 ? 'btn-primary' : ''}`}
onClick={handleSwitchList}
>
List 2
</button>
</div>
{
displayList1
? list[1]?.map((item) => (
<SwipeableListItem onSwipe={() => handleSendToSecondList(item.id, list[0], list[1])}>
<p>{item.id}</p>
</SwipeableListItem>
))
: list[0]?.map((item) => (
<SwipeableListItem>
<p>{item.id}</p>
</SwipeableListItem>
))
}
</div>
);
};
export default MyList;
我创建这个只是为了显示正在发生的事情 https://codesandbox.io/s/react-hooks-usestate-kbvqt?file=/src/index.js
问题在这里发生,但有所不同。有两个列表,如果您从第一个列表中滑动一个项目,则第二个列表中的项目将消失,因为它具有css属性。