Reactjs 如何在双嵌套子组件网(带挂钩)中从父组件优化更新状态?
您好,目前我的问题是,当我单击Delete按钮(在SortableItem组件中找到)时,当变异成功工作时,它需要刷新以显示删除。运行DeleteButton后,最理想的刷新方式是什么?我相信这需要我更新SortableItem组件中RankList组件的状态,但我想知道实现这一点的最佳方法 RankList.jsReactjs 如何在双嵌套子组件网(带挂钩)中从父组件优化更新状态?,reactjs,graphql,Reactjs,Graphql,您好,目前我的问题是,当我单击Delete按钮(在SortableItem组件中找到)时,当变异成功工作时,它需要刷新以显示删除。运行DeleteButton后,最理想的刷新方式是什么?我相信这需要我更新SortableItem组件中RankList组件的状态,但我想知道实现这一点的最佳方法 RankList.js import React, { useContext, useEffect, useRef, useState } from "react"; import gql from "gr
import React, { useContext, useEffect, 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 DeleteButton from "../components/DeleteButton";
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";
// function SortableItem({ value, listId, listItemId }) {
// return SortableElement(() => (
// <>
// <li className="listLI">{value}</li>
// <DeleteButton listId={listId} listItemId={listItemId} />
// </>
// ));
// }
const SortableItem = SortableElement(
({ deleteItem, value, listId, listItemId }) => (
<>
<li className="listLI">{value}</li>
<DeleteButton
listId={listId}
listItemId={listItemId}
deleteItem={deleteItem}
/>
</>
)
);
const SortableList = SortableContainer(({ deleteItem, items, listId }) => {
return (
<ol className="theList">
{/* <CSSTransitionGroup
transitionName="ranklist"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
> */}
{items.map((item, index) => (
<SortableItem
deleteItem={deleteItem}
listId={listId}
listItemId={item.id}
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,
},
// onError(err) {
// console.log(err.graphQLErrors[0].extensions.exception.errors);
// // setErrors(err.graphQLErrors[0].extensions.exception.errors);
// }
});
useEffect(() => {
if (data && data.getList && data.getList.listItems) {
setState(() => ({ items: data.getList.listItems }));
}
}, [data]);
// const [state, setState] = useState({ items: data.getList.listItems });
const deleteItem = (listItem) => {
let temp = state.items.filter((item) => item.id !== listItem);
console.log(temp);
setState(() => ({ items: temp }));
};
const [submitListItem] = useMutation(SUBMIT_LIST_ITEM_MUTATION, {
update() {
setListItem("");
listItemInputRef.current.blur();
},
variables: {
listId,
body: listItem,
},
});
const [editListItems] = useMutation(EDIT_LIST_ITEMS_MUTATION, {
variables: {
listId,
listItems: state.items,
},
});
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),
}));
state.items.map((list) => delete list["__typename"]);
editListItems();
}
let listMarkup;
if (!data.getList) {
listMarkup = <p>Loading list...</p>;
} else {
const {
id,
title,
createdAt,
username,
listItems,
comments,
likes,
likeCount,
commentCount,
} = data.getList;
console.log(id);
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
deleteItem={deleteItem}
items={state.items}
listId={id}
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"
/> */}
<ol className="theList">
{/* <CSSTransitionGroup
transitionName="ranklist"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
> */}
{listItems.map((item, index) => (
<li
className="listLI"
key={`item-${item.id}`}
index={index}
value={item.body}
>
{item.body}
</li>
))}
{/* </CSSTransitionGroup> */}
</ol>
</div>
</div>
);
}
return listMarkup;
}
const EDIT_LIST_ITEMS_MUTATION = gql`
mutation($listId: ID!, $listItems: [ListItems]!) {
editListItems(listId: $listId, listItems: $listItems) {
id
listItems {
id
body
createdAt
username
}
}
}
`;
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;
import React, { useState } from "react";
import gql from "graphql-tag";
import { useMutation } from "@apollo/react-hooks";
import { Button, Confirm, Icon } from "semantic-ui-react";
import { FETCH_LISTS_QUERY, FETCH_LIST_QUERY } from "../util/graphql";
import MyPopup from "../util/MyPopup";
function DeleteButton({ listId, listItemId, commentId, deleteItem, callback }) {
const [confirmOpen, setConfirmOpen] = useState(false);
let mutation;
if (listItemId) {
mutation = DELETE_LIST_ITEM_MUTATION;
} else if (commentId) {
mutation = DELETE_COMMENT_MUTATION;
} else {
mutation = DELETE_LIST_MUTATION;
}
// const mutation = commentId ? DELETE_COMMENT_MUTATION : DELETE_LIST_MUTATION;
const [deleteListOrComment] = useMutation(mutation, {
update(proxy) {
setConfirmOpen(false);
// remove list from cache
if (!commentId && !listItemId) {
const data = proxy.readQuery({
query: FETCH_LISTS_QUERY,
});
const resLists = data.getLists.filter((p) => p.id !== listId);
proxy.writeQuery({
query: FETCH_LISTS_QUERY,
data: { getLists: [...resLists] },
});
}
if (callback) callback();
},
variables: {
listId,
listItemId,
commentId,
},
onError(err) {
console.log(err.graphQLErrors[0].extensions.exception.errors);
},
});
return (
<>
<MyPopup content={commentId ? "Delete comment" : "Delete list"}>
<Button
as="div"
color="red"
floated="right"
onClick={(e) => {
e.preventDefault();
setConfirmOpen(true);
}}
>
<Icon name="trash" style={{ margin: 0 }} />
</Button>
</MyPopup>
<Confirm
open={confirmOpen}
onCancel={(e) => {
e.preventDefault();
setConfirmOpen(false);
}}
onConfirm={(e) => {
e.preventDefault();
deleteListOrComment();
deleteItem(listItemId);
}}
/>
</>
);
}
const DELETE_LIST_MUTATION = gql`
mutation deleteList($listId: ID!) {
deleteList(listId: $listId)
}
`;
const DELETE_LIST_ITEM_MUTATION = gql`
mutation deleteListItem($listId: ID!, $listItemId: ID!) {
deleteListItem(listId: $listId, listItemId: $listItemId) {
id
comments {
id
username
createdAt
body
}
commentCount
}
}
`;
const DELETE_COMMENT_MUTATION = gql`
mutation deleteComment($listId: ID!, $commentId: ID!) {
deleteComment(listId: $listId, commentId: $commentId) {
id
comments {
id
username
createdAt
body
}
commentCount
}
}
`;
export default DeleteButton;
import React,{useContext,useffect,useRef,useState}来自“React”;
从“graphql标签”导入gql;
从“@apollo/react hooks”导入{useQuery,useVaritation}”;
从“语义ui反应”导入{Form};
从“时刻”中导入时刻;
从“./组件/DeleteButton”导入DeleteButton;
从“./context/auth”导入{AuthContext};
从“react-sortable hoc”导入{SortableContainer,SortableElement};
从“阵列移动”导入阵列移动;
导入“./RankList.css”;
从“反应转换组”导入{CSSTransitionGroup};
//函数SortableItem({value,listId,listItemId}){
//返回可排序元素(()=>(
//
//{value}
//
//
// ));
// }
const SortableItem=SortableElement(
({deleteItem,value,listId,listItemId})=>(
{value}
)
);
const SortableList=SortableContainer({deleteItem,items,listId})=>{
返回(
{/* */}
{items.map((项,索引)=>(
))}
{/* */}
);
});
功能等级列表(道具){
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\u LIST\u QUERY{
变量:{
listId,
},
//ONERR(错误){
//日志(err.graphQLErrors[0].extensions.exception.errors);
////setErrors(err.graphQLErrors[0].extensions.exception.errors);
// }
});
useffect(()=>{
if(data&&data.getList&&data.getList.listItems){
setState(()=>({items:data.getList.listItems}));
}
},[数据];
//const[state,setState]=useState({items:data.getList.listItems});
常量deleteItem=(listItem)=>{
让temp=state.items.filter((item)=>item.id!==listItem);
控制台日志(temp);
setState(()=>({items:temp}));
};
常量[submitListItem]=使用突变(提交列表项突变{
更新(){
setListItem(“”);
listItemInputRef.current.blur();
},
变量:{
listId,
正文:清单项目,
},
});
常量[editListItems]=使用变异(编辑列表项变异{
变量:{
listId,
listItems:state.items,
},
});
如果(加载)返回加载…;
如果(错误)返回错误..;
函数deleteListCallback(){
props.history.push(“/”);
}
onSortEnd({oldIndex,newIndex})函数{
setState(({items})=>({
项目:arrayMove(项目、旧索引、新索引),
}));
state.items.map((list)=>delete list[“\uu typename”]);
editListItems();
}
让列表标记;
如果(!data.getList){
listMarkup=加载列表…;
}否则{
常数{
身份证件
标题
创建数据,
用户名,
清单项目,
评论,
喜欢,
比如说,
伯爵,
}=data.getList;
console.log(id);
listMarkup=用户(
{title}
setListItem(event.target.value)}
ref={listItemInputRef}
/>
提交
) : (
{props.title}
{/* */}
{/* */}
{listItems.map((项,索引)=>(
{item.body}
))}
{/* */}
);
}
返回列表标记;
}
常量编辑\列表\项目\变异=gql`
突变($listId:ID!,$listItems:[listItems]!){
editListItems(listId:$listId,listItems:$listItems){
身份证件
列表项{
身份证件
身体
创建数据
用户名
}
}
}
`;
const SUBMIT\u LIST\u ITEM\u MUTATION=gql`
突变($listId:ID!,$body:String!){
createListItem(listId:$listId,body:$body){
身份证件
列表项{
身份证件
身体
创建数据
用户名
}
评论{
身份证件
身体
创建数据
用户名
}
评论计数
}
}
`;
const FETCH\u LIST\u QUERY=gql`
查询($listId:ID!){
getList(listId:$listId){
身份证件
标题
创建数据
用户名
列表项{
身份证件
创建数据
用户名
身体
}
利克蒙特
喜欢{
用户名
}
评论计数
评论{
身份证件
用户名
创建数据
身体
}
}
}
`;
导出默认RankList;
DeleteButton.js
import React, { useContext, useEffect, 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 DeleteButton from "../components/DeleteButton";
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";
// function SortableItem({ value, listId, listItemId }) {
// return SortableElement(() => (
// <>
// <li className="listLI">{value}</li>
// <DeleteButton listId={listId} listItemId={listItemId} />
// </>
// ));
// }
const SortableItem = SortableElement(
({ deleteItem, value, listId, listItemId }) => (
<>
<li className="listLI">{value}</li>
<DeleteButton
listId={listId}
listItemId={listItemId}
deleteItem={deleteItem}
/>
</>
)
);
const SortableList = SortableContainer(({ deleteItem, items, listId }) => {
return (
<ol className="theList">
{/* <CSSTransitionGroup
transitionName="ranklist"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
> */}
{items.map((item, index) => (
<SortableItem
deleteItem={deleteItem}
listId={listId}
listItemId={item.id}
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,
},
// onError(err) {
// console.log(err.graphQLErrors[0].extensions.exception.errors);
// // setErrors(err.graphQLErrors[0].extensions.exception.errors);
// }
});
useEffect(() => {
if (data && data.getList && data.getList.listItems) {
setState(() => ({ items: data.getList.listItems }));
}
}, [data]);
// const [state, setState] = useState({ items: data.getList.listItems });
const deleteItem = (listItem) => {
let temp = state.items.filter((item) => item.id !== listItem);
console.log(temp);
setState(() => ({ items: temp }));
};
const [submitListItem] = useMutation(SUBMIT_LIST_ITEM_MUTATION, {
update() {
setListItem("");
listItemInputRef.current.blur();
},
variables: {
listId,
body: listItem,
},
});
const [editListItems] = useMutation(EDIT_LIST_ITEMS_MUTATION, {
variables: {
listId,
listItems: state.items,
},
});
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),
}));
state.items.map((list) => delete list["__typename"]);
editListItems();
}
let listMarkup;
if (!data.getList) {
listMarkup = <p>Loading list...</p>;
} else {
const {
id,
title,
createdAt,
username,
listItems,
comments,
likes,
likeCount,
commentCount,
} = data.getList;
console.log(id);
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
deleteItem={deleteItem}
items={state.items}
listId={id}
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"
/> */}
<ol className="theList">
{/* <CSSTransitionGroup
transitionName="ranklist"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
> */}
{listItems.map((item, index) => (
<li
className="listLI"
key={`item-${item.id}`}
index={index}
value={item.body}
>
{item.body}
</li>
))}
{/* </CSSTransitionGroup> */}
</ol>
</div>
</div>
);
}
return listMarkup;
}
const EDIT_LIST_ITEMS_MUTATION = gql`
mutation($listId: ID!, $listItems: [ListItems]!) {
editListItems(listId: $listId, listItems: $listItems) {
id
listItems {
id
body
createdAt
username
}
}
}
`;
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;
import React, { useState } from "react";
import gql from "graphql-tag";
import { useMutation } from "@apollo/react-hooks";
import { Button, Confirm, Icon } from "semantic-ui-react";
import { FETCH_LISTS_QUERY, FETCH_LIST_QUERY } from "../util/graphql";
import MyPopup from "../util/MyPopup";
function DeleteButton({ listId, listItemId, commentId, deleteItem, callback }) {
const [confirmOpen, setConfirmOpen] = useState(false);
let mutation;
if (listItemId) {
mutation = DELETE_LIST_ITEM_MUTATION;
} else if (commentId) {
mutation = DELETE_COMMENT_MUTATION;
} else {
mutation = DELETE_LIST_MUTATION;
}
// const mutation = commentId ? DELETE_COMMENT_MUTATION : DELETE_LIST_MUTATION;
const [deleteListOrComment] = useMutation(mutation, {
update(proxy) {
setConfirmOpen(false);
// remove list from cache
if (!commentId && !listItemId) {
const data = proxy.readQuery({
query: FETCH_LISTS_QUERY,
});
const resLists = data.getLists.filter((p) => p.id !== listId);
proxy.writeQuery({
query: FETCH_LISTS_QUERY,
data: { getLists: [...resLists] },
});
}
if (callback) callback();
},
variables: {
listId,
listItemId,
commentId,
},
onError(err) {
console.log(err.graphQLErrors[0].extensions.exception.errors);
},
});
return (
<>
<MyPopup content={commentId ? "Delete comment" : "Delete list"}>
<Button
as="div"
color="red"
floated="right"
onClick={(e) => {
e.preventDefault();
setConfirmOpen(true);
}}
>
<Icon name="trash" style={{ margin: 0 }} />
</Button>
</MyPopup>
<Confirm
open={confirmOpen}
onCancel={(e) => {
e.preventDefault();
setConfirmOpen(false);
}}
onConfirm={(e) => {
e.preventDefault();
deleteListOrComment();
deleteItem(listItemId);
}}
/>
</>
);
}
const DELETE_LIST_MUTATION = gql`
mutation deleteList($listId: ID!) {
deleteList(listId: $listId)
}
`;
const DELETE_LIST_ITEM_MUTATION = gql`
mutation deleteListItem($listId: ID!, $listItemId: ID!) {
deleteListItem(listId: $listId, listItemId: $listItemId) {
id
comments {
id
username
createdAt
body
}
commentCount
}
}
`;
const DELETE_COMMENT_MUTATION = gql`
mutation deleteComment($listId: ID!, $commentId: ID!) {
deleteComment(listId: $listId, commentId: $commentId) {
id
comments {
id
username
createdAt
body
}
commentCount
}
}
`;
export default DeleteButton;
import React,{useState}来自“React”;
从“graphql标签”导入gql;
从“@apollo/react hooks”导入{useStation}”;
从“语义ui反应”导入{按钮、确认、图标};
从“./util/graphql”导入{FETCH_LIST_QUERY,FETCH_LIST_QUERY};
从“./util/MyPopup”导入MyPopup;
函数DeleteButton({listId,listimeid,commentId,deleteem,callback}){
const[confirmOpen,setConfirmOpen]=useState(false);
让突变;
if(listItemId){
突变=删除列表项_