删除影响 DOM 中某些内容的内容时出现 NotFoundError

NotFoundError when deleting something that affects something in the DOM

我创建了一个笔记应用程序。在首页上有类别和注释。您可以单击类别并获取该类别下的所有笔记。我刚刚添加了一个按钮,可以让您删除该类别及其所有注释,然后导航回首页。它看起来像这样:

按钮:


<IonRow>
    <IonButton onClick={deletecat} >
        Delete Category
    </IonButton>
</IonRow>

这里是 deletecat 函数:

const deletecat = () => {
        const trashcategory = ({category}) => {
        try {
        fetch(`https://fakeurl.com/delcat/${category}/`, {
        method: "DELETE",
        mode: "cors",
        headers: {
        "Content-Type": "application/json",
        },
        })
        } catch (error) {
        console.log("error time!", error);
        return false;
        }
        };
    trashcategory({category})
    router.push('/notes')
    }

当我点击我的按钮时出现这个错误:

NotFoundError: Node.removeChild: The node to be removed is not a child of this node

这个问题实际上是在 SO 之前 (React Error: NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node) 上解决的,但他们的具体解决方案是针对 jquery。但是我觉得概念是一样的:

This issue occurs when you:

1. Render something using React
2. Then, you manipulate DOM rendered by React with external script
3. Now on the next render cycle(re-render), React doesn't find the DOM node it rendered previously as its already modified/removed by external script

我该如何解决这个问题?有什么方法可以重新渲染 DOM ,而不会尝试查找之前渲染的内容?我还能如何解决这个问题?

编辑:这是首页:


    useEffect(() => {

        getcategories({username})



        getnotes({username})

        console.log("USEEFFECTTIME")


    },[]);


    const getcategories = ({ username }) => {
        
    try {
    
    fetch(`https://fakeurl.com/getcategories`, {
    method: "POST",
    mode: "cors",
    headers: {
    "Content-Type": "application/json",
    },
    body: JSON.stringify({username}),
    })
    .then(res => res.json())
    .then(data => {
        setCategorydata(data);
        setLoading(false);
    })
    } catch (error) {
    console.log("error time!", error);
    return false;
    }
    };
    console.log('before get categories')





    const getnotes = async ({ username }) => {
    
    try {
    //await fetch(`/getnotes`, {
    await fetch(`https://fakeurl.com/getnotes`, {
    method: "POST",
    mode: "cors",
    headers: {
    "Content-Type": "application/json",
    },
    body: JSON.stringify({username}),
    })
    .then(res => res.json())
    .then(data2 => {
        setNotedata(data2);
        setLoading2(false)
    })
    } catch (error) {
    console.log("error time!", error);
        return false;
    }
    };

const categories = categorydata.categories
const notes = notedata.notes


<IonSlides id="slider" options={{ slidesPerView: "auto", zoom: true, grabCursor: true }} className={ `${ styles.categorySlider } ion-padding-bottom` }>
                    { categories.map((category, index) => {

                        const noteCount = notes.filter(n => n.note_category === category.id).length;

                        return (

                            <IonSlide key={ `categorySlide_${ index }`}>
                                <IonCol className="ion-text-left">
                                    <IonCard routerLink={`/categorypage/${category.id}`}>
                                        <IonCardHeader className="ion-no-padding" >

                                            <div className={ styles.slideCount }>
                                                <h6>{ noteCount } { noteCount === 1 ? "note" : "notes" } </h6>
                                            </div>
                                            <div className={ styles.slideHeader }>
                                                <h4 style={{color:"black"}}>{ category.category }</h4>
                                            </div>
                                        </IonCardHeader>

                                        <IonCardContent>
                                            <div className={ styles.categoryColor } style={{ borderBottom: `2px solid ${ category.color }` }}></div>
                                        </IonCardContent>
                                    </IonCard>
                                </IonCol>
                            </IonSlide>
                        );
                    })}
                </IonSlides>
                
                <IonGrid className={ styles.bottomContainer }>
                    <IonRow>
                        <IonCol size="12" className="ion-padding-start">
                            <IonCardSubtitle className={ styles.heading }>
                                Recent Notes
                            </IonCardSubtitle>
                        </IonCol>
                    </IonRow>
                    
                    <div className={ styles.recentNotes }>

                        { notes.slice(0).reverse().map((note, index) => {

                            return (

                                <IonRow key={ `note_${ index }` } className="animate__animated animate__faster" id={ `noteRow_${ note.id }` }>
                                    <IonCol size="12">
                                        <Link to={`/Update/${note.id}`}>
                                            <h2>{note.note_name}</h2>
                                        </Link>
                                    </IonCol>
                                </IonRow>
                            );
                        })}
                    </div>
                </IonGrid>

根据您上面的评论,要使更改同时反映在首页和组件页面上,您可以在父组件级别从 API 调用数据,然后将数据和 setData 向下传递为组件页面的道具。

如果首页和组件页是router下的兄弟,那么可以在router组件中拉取数据,share as props or implement the useContext hook共享数据

更改笔记内容和删除类别等更新应该发生在 front-end 上,然后通过异步获取请求更新到 back-end。

问题来自 API 的更新之间的异步延迟与调用 router.push 方法的同步卸载竞争。通过依赖本地状态数据,你应该摆脱你的问题。