Home > Software engineering >  UseState change not triggering DOM update after API call
UseState change not triggering DOM update after API call

Time:02-04

I'm trying to populate a rich text editor (tiptap.dev) with the response from an API call. After calling the setEditorContent hook with the data payload, the editor content should update. I notice that when I modify the local file and save it, the API data is rendered in the DOM (but not on the initial page load).

export default function EditHandbook() {
  const router = useRouter();
  const user = useUser();
  const { query } = useRouter();

  const [loading, setLoading] = useState(true);
  const [editorContent, setEditorContent] = useState(null);

  // Get handbook by ID
  const id = query.id;
  let handbookText = null;
  function loadDataOnlyOnce() {
    axios
      .get("/api/templater/"   id   "/")
      .then((res) => {
        handbookText = res.data.handbookContent; // the object returned from api/templater/[id].js
      })
      .finally(() => {
        setEditorContent(handbookText);
        setLoading(false);
      })
      .catch((err) => console.log(err));
  }

  useEffect(() => {
    loadDataOnlyOnce();
  }, [id]); // only run once, after id is resolved from router on page load

  const editor = useEditor({
    extensions: [StarterKit],
    onUpdate({ editor }) {
      setEditorContent(editor.getHTML());
    },
    content: editorContent,
  });

  return (
    <div>
      <TextEditorMenubar editor={editor} />
      <EditorContent editor={editor} />
    </div>
  );
}

CodePudding user response:

You should wrap id in a useState. This worked for me

const router = useRouter();
const [id, setId] = useState(router.query.id);

useEffect(() => {
    setId(router.query.id);
    // Test if the id is not null
    if (id) {
        loadDataOnlyOnce();
    }
}, [router, id]);

Also pass the router object to the useEffect so react knows to fire that function when the router changes.

CodePudding user response:

I think you should add:

if (loading) return "something is loading";

return (
  <div>
    <TextEditorMenubar editor={editor} />
    <EditorContent editor={editor} />
  </div>
);

and don't do a useEffect(() => setId(id), [id]) because you will rerendering forever. In case you need, do it be behind an if to control it

  •  Tags:  
  • Related