vakata / jstree

jquery tree plugin
http://jstree.com
MIT License
5.15k stars 1.38k forks source link

Refresh in react? #2585

Closed stesvis closed 2 years ago

stesvis commented 2 years ago

Hello I was wondering if anybody knows how to properly refresh the treeview when the data changes, in React. On the first page load it's working fine, but sometimes I need to click a refresh button to get current data, and this is best I could come up with so far: destroy and recreate when the data changes.

  useEffect(() => {
    // step 1: destroy
    $('#myTreeView').jstree("destroy").empty();

    // step 2: recreate
    $('#myTreeView')
      .jstree({
        core: {
          themes: {
            responsive: false,
          },
          data: data,
        },
        plugins: ["checkbox"],
      })
      // listen for event
      .on("changed.jstree", function (e, data) {
        handleSelectionChanged(data);
      });

    return () => {};
  }, [data]);

It works, but the UX is not great as you can see the treeview "flashing" while it's recreating... Any better way?

Thanks.

stesvis commented 2 years ago

I also tried this other solution, using the refresh method, but even if some of my nodes have the selected: true option, the checkboxes are unchecked (only after a refresh, even reloading the same data):

  useEffect(() => {
    // create the jstree on component load
    $('#myTreeView')
      .jstree({
        core: {
          themes: {
            responsive: false,
          },
        },
        plugins: ["checkbox"],
      })
      // listen for event
      .on("changed.jstree", function (e, data) {
        handleSelectionChanged(data);
      });

    return () => {
      $('#myTreeView').jstree("destroy");
    };
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    // refresh the jstree with new data
    $('#myTreeView').jstree(true).settings.core.data = data;
    $('#myTreeView').jstree(true).refresh();

    return () => {};
  }, [data]);
vakata commented 2 years ago

I am not very good with react, but my guess is you need the second parameter of refresh - it manages how the current state is reapplied. By default it takes the currently selected nodes BEFORE calling refresh, refreshes and the reapplies the state. If you pass true as a the second argument it will forget the state and use only what you provided. The state also includes opened nodes. Let me know if this does not solve the issue and I will reopen right away.