如何在 React 中使用 useState() 渲染组件之前使用 useNavigate()

Ale*_*kiy 6 reactjs react-apollo apollo-client react-hooks

我正在使用 React 和 apollo-client。如果用户不是注释的所有者,则应重定向该注释。但重定向后我收到:Warning: Cannot update a component ('BrowserRouter') while rendering a different component ('EditNote'). To locate the bad setState() call inside 'EditNote'。据我了解,组件中存在useState()问题<NoteForm/>。我做错了什么?

import React, { useEffect } from "react";
import { useMutation, useQuery } from "@apollo/client";
import { useNavigate, useParams } from "react-router-dom";

import NoteForm from "../components/NoteForm";

import { GET_NOTE, GET_ME } from "../gql/query";
import { EDIT_NOTE } from "../gql/mutation";

const EditNote = () => {
    const navigate = useNavigate();
    const params = useParams();
    const id = params.id;

    const [editNote] = useMutation(EDIT_NOTE, {
        variables: {
            id
        },
        onCompleted: () => {
            navigate(`/note/${id}`, { replace: true });
        }
    });

    const { loading: noteLoading, error: noteError, data: noteData } = useQuery(GET_NOTE, { variables: { id } });
    const { loading: userLoading, error: userError, data: userData } = useQuery(GET_ME);


    if (noteLoading || userLoading) return 'Loading...';
    if (noteError || userError) return `Error! ${error.message}`;

    if (userData.me.id !== noteData.note.author.id) {
        navigate(`/note/${id}`, { replace: true });
    }

    return <NoteForm content={noteData.note.content} action={editNote} />;



};

export default EditNote;
Run Code Online (Sandbox Code Playgroud)

如果使用包装重定向useEffect()将收到错误Uncaught TypeError: Cannot read properties of undefined (reading 'me'),因为请求未完成。因此,也许我应该以某种方式“等待”,直到请求未完成或以某种方式将请求加入到一个useQuery().

    const { loading: noteLoading, error: noteError, data: noteData } = useQuery(GET_NOTE, { variables: { id } });
    const { loading: userLoading, error: userError, data: userData } = useQuery(GET_ME);

    useEffect(() => {
        if (userData.me.id !== noteData.note.author.id) {
            navigate(`/note/${id}`, { replace: true });
        }
    }, [userData, noteData]);

    if (noteLoading || userLoading) return 'Loading...';
    if (noteError || userError) return `Error! ${error.message}`;

    return <NoteForm content={noteData.note.content} action={editNote} />;
Run Code Online (Sandbox Code Playgroud)

这是NoteForm组件,其中是useState()。

import React, { Component, useState } from "react";
import styled from 'styled-components';

import Button from './Button';

const Wrapper = styled.div`
    height: 100%;
`;
const Form = styled.form`
    height: 100%;
`;
const TextArea = styled.textarea`
    width: 100%;
    height: 90%;
`;

const NoteForm = props => {
    const [value, setValue] = useState({ content: props.content || '' });

    const onChange = event => {
        setValue({
            ...value,
            [event.target.name]: event.target.value
        });
    };

    return (
        <Wrapper>
            <Form onSubmit={e => {
                e.preventDefault();
                props.action({
                    variables: { ...value }
                });
            }}
            >
                <TextArea required type="text" name="content" placeholder="Note content"
                    value={value.content}
                    onChange={onChange}
                />
                <Button type="submit">Save</Button>
            </Form>
        </Wrapper>
    );
};

export default NoteForm;
Run Code Online (Sandbox Code Playgroud)

Sha*_*Amr 1

我不确定,但试试这个:

首先在父组件中更新这一行:

if (userData.me.id !== noteData.note.author.id) {
    return navigate(`/note/${id}`, { replace: true });
 }
Run Code Online (Sandbox Code Playgroud)

然后在子组件中我想这样做:

const NoteForm = ({content = "", action}) => {
    const [value, setValue] = useState(content);

    const onChange = event => {
        setValue(event.target.value);
    };
.....

// then in the render of text area we only need a flat state contains value

<TextArea
  required
  type="text"
  name="content"
  placeholder="Note content"
  value={value}
  onChange={onChange}
/>
Run Code Online (Sandbox Code Playgroud)

但如果不起作用,请尝试根据 content 的值在 useEffect 中设置状态,不要忘记给状态一个初始值“”:

useEffect(() => {
   if (content) {
     setValue(content);
   }
}, [content]);
Run Code Online (Sandbox Code Playgroud)