Link with sample gif of issue here!
你好,我正在创建一个允许用户创建列表的应用程序(所有数据都存储在mongoDB上并可以通过Apollo GraphQL访问);每个列表都有一个属性listItems,这是一个存储列表中所有项目的数组。
[当用户转到单独的Ranklist.js组件页面时,它将加载列表以及通过graphQL查询访问的所有列表项。
[此应用从此处利用react-sortable-hoc允许用户在其中移动列表项。尽管我能够移动listItems,但是一旦放开,页面就会重置顺序以匹配存储在mongoDB上的数组的顺序。
[请告知我为什么会这样,以及如何正确地实现一种方法,通过Apollo graphQL将react-sortable-hoc与数据库一起保存列表的顺序。
import React, { useContext, useRef, useState } from "react";
import gql from "graphql-tag";
import { useQuery, useMutation } from "@apollo/react-hooks";
import {
Form,
} from "semantic-ui-react";
import moment from "moment";
import { AuthContext } from "../context/auth";
import { SortableContainer, SortableElement } from "react-sortable-hoc";
import arrayMove from "array-move";
import "../RankList.css";
import { CSSTransitionGroup } from "react-transition-group";
const SortableItem = SortableElement(({ value }) => (
<li className="listLI">{value}</li>
));
const SortableList = SortableContainer(({ items }) => {
return (
<ol className="theList">
<CSSTransitionGroup
transitionName="ranklist"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
>
{items.map((item, index) => (
<SortableItem
key={`item-${item.id}`}
index={index}
value={item.body}
/>
))}
</CSSTransitionGroup>
</ol>
);
});
function RankList(props) {
const listId = props.match.params.listId;
const { user } = useContext(AuthContext);
const listItemInputRef = useRef(null);
const [state, setState] = useState({ items: [] });
const [listItem, setListItem] = useState("");
const { loading, error, data } = useQuery(FETCH_LIST_QUERY, {
variables: {
listId,
},
});
const [submitListItem] = useMutation(SUBMIT_LIST_ITEM_MUTATION, {
update() {
setListItem("");
listItemInputRef.current.blur();
},
variables: {
listId,
body: listItem,
},
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error..</p>;
function deleteListCallback() {
props.history.push("/");
}
function onSortEnd({ oldIndex, newIndex }) {
setState(({ items }) => ({
items: arrayMove(items, oldIndex, newIndex),
}));
}
let listMarkup;
if (!data.getList) {
listMarkup = <p>Loading list...</p>;
} else {
const {
id,
title,
createdAt,
username,
listItems,
comments,
likes,
likeCount,
commentCount,
} = data.getList;
listMarkup = user ? (
<div className="todoListMain">
<div className="rankListMain">
<div className="rankItemInput">
<h3>{title}</h3>
<Form>
<div className="ui action input fluid">
<input
type="text"
placeholder="Choose rank item.."
name="listItem"
value={listItem}
onChange={(event) => setListItem(event.target.value)}
ref={listItemInputRef}
/>
<button
type="submit"
className="ui button teal"
disabled={listItem.trim() === ""}
onClick={submitListItem}
>
Submit
</button>
</div>
</Form>
</div>
<SortableList
items={listItems}
onSortEnd={onSortEnd}
helperClass="helperLI"
/>
</div>
</div>
) : (
<div className="todoListMain">
<div className="rankListMain">
<div className="rankItemInput">
<h3>{props.title}</h3>
</div>
<SortableList
items={listItems}
onSortEnd={onSortEnd}
helperClass="helperLI"
/>
</div>
</div>
);
}
return listMarkup;
}
const SUBMIT_LIST_ITEM_MUTATION = gql`
mutation($listId: ID!, $body: String!) {
createListItem(listId: $listId, body: $body) {
id
listItems {
id
body
createdAt
username
}
comments {
id
body
createdAt
username
}
commentCount
}
}
`;
const FETCH_LIST_QUERY = gql`
query($listId: ID!) {
getList(listId: $listId) {
id
title
createdAt
username
listItems {
id
createdAt
username
body
}
likeCount
likes {
username
}
commentCount
comments {
id
username
createdAt
body
}
}
}
`;
export default RankList;
您的onSortEnd
函数调用setState
并相应地更新state.items
,但是您永远不会在组件中使用state.items
,而是直接使用data.getList.listItems
。由于该值在最初获取后不会更改,因此您的列表保持不变。
您应该改用state.items
。然后,只要useEffect
的值发生更改,就可以使用state.items
更新listItems
-例如,最初是在返回服务器的响应或响应突变时。类似于:
onEffect(() => {
if (data && data.getList && data.getList.listItems) {
setState(() => ({ items: data.getList.listItems }))
}
}, [data])