Recoil: [discussion] DevTools

Created on 28 May 2020  路  12Comments  路  Source: facebookexperimental/Recoil

Not sure what people have in mind or are working on, but figured it would be good to centralize discussion.

devtools enhancement

Most helpful comment

https://twitter.com/jaredpalmer/status/1266385084367732736?s=20 馃憖
This looks rad @jaredpalmer!

My Recoil devtools wishlist would be:

  1. switch between different recoil roots
  2. search/filter the list of atom/selectors by name
  3. group history into the scheduler's transactions (so can see which values all changes together at the same time, verses which values changed separately)
  4. see number of active subscriptions for an atom/selector
  5. a dropdown style tree of selector dependencies
  6. manually update/reset/jump-back-to-a-previous-value of an atom
  7. for the added code to expose these types of hooks to not add too much size to recoil in production

All 12 comments

Yup! We've prototyped a little and have a project planned to develop. But, would be interesting to hear what ideas the community has. I'm working on tweaking the observability hook to improve support for debug tools.

I'm thinking a sort of tree view for all the state would be cool, if a convention for "namespace" atoms forms! So for instance if people start using Module/Key as "zones/contexts" as per this comment https://github.com/facebookexperimental/Recoil/issues/181#issuecomment-635003783, we'd be able to visualize state in a tree view where each / is a branch and as if state were a complex object instead of a flat list of keys internally.

Another idea would be being able to "watch" specific atoms in a watchlist for debugging things related to specific parts of state.

re: entire tree

  • breakdwon by atoms, around naming convention /
  • see diff on a given atom (use deep-diff)
  • see atom history

btw the code in https://recoiljs.org/docs/guides/persistence#saving-state doesn't work. atomValues.get() doesn't return the value just metadata about persistence. it's hard to prototype without this working.

@jaredpalmer - were you looking at atomInfo instead of atomValues?

Hrm, here when trying something similar atomValues seems to always be empty.

NOTE: this is not a desired implementation just what I used for quick feedback.

  useTransactionObservation_UNSTABLE((update) => {
    const { atomValues, modifiedAtoms } = update;
    const tag = `State Change ${new Date().toISOString()}`;

    console.group(tag);
    console.log(update);
    for (const key of modifiedAtoms) {
      console.log(key, atomValues.get(key));
    }
    console.groupEnd();
  });

What I'm really looking forward to is a visualization of the data-flow graph of atoms, selectors, and subscribing components, with the ability to see current values and annotations/history on what has changed and how it has propagated through the graph.

@smacpherson64 useTransactionObservation_UNSTABLE is not a published API yet, the new API is under development and I hope to have it out soon. Some things to keep in mind is that the current implementation was done for persistence, not debugging. So, it only reports atoms values for atoms with special metadata marking them for persistence. (The atom has a persistence_UNSTABLE property with a non-null type property. #209) It also doesn't report selectors. Both issues will be addressed in the new API.

useTransactionObservation_UNSTABLE is not a published API yet, the new API is under development and I hope to have it out soon.

@drarmstr For sure! Just wanted to add to the conversation around atomValues!

So, it only reports atoms values for atoms with special metadata marking them for persistence. (The atom has a persistence_UNSTABLE property with a non-null type property. It also doesn't report selectors. Both issues will be addressed in the new API.

Ahhh, makes sense! Recoil is powerful, excited to watch it evolve!

https://twitter.com/jaredpalmer/status/1266385084367732736?s=20 馃憖
This looks rad @jaredpalmer!

My Recoil devtools wishlist would be:

  1. switch between different recoil roots
  2. search/filter the list of atom/selectors by name
  3. group history into the scheduler's transactions (so can see which values all changes together at the same time, verses which values changed separately)
  4. see number of active subscriptions for an atom/selector
  5. a dropdown style tree of selector dependencies
  6. manually update/reset/jump-back-to-a-previous-value of an atom
  7. for the added code to expose these types of hooks to not add too much size to recoil in production

Hi everyone! I'm working on this right now!

Both packages can be found in this Github repository, in which i'm creating devtools for recoil based on existing redux devtools and other projects. In future, more devtools and docs will be available!

I used an empty redux store to mirror the changes the from recoil to redux devtool extension by observing state changes in recoil.

Time traveling and probably most redux features does not work, but the redux devtool extension is integrated nicely into react native debugger so it's good enough for me.

If anyone is interested, here's a snippet:

import { useEffect } from "react";
import { useRecoilSnapshot } from "recoil";
import { createStore } from "redux";

/**
 * Usage:
 * const App = () => (
 *   <RecoilRoot>
 *     <RecoilDebugObserver />
 *     <AppEntryComponent />
 *   </RecoilRoot>
 * );
 */
let RecoilDebugObserver = () => null;

const reduxDevtoolsExtension =
  typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION__;

if (reduxDevtoolsExtension) {
  const reducer = (state = {}, { type, payload }) => {
    if (String(type).startsWith("[recoil]")) {
      return { ...state, [payload.node.key]: payload.loadable };
    } else {
      return state;
    }
  };

  const store = createStore(
    reducer,
    reduxDevtoolsExtension({
      name: "recoil debug observer",
      maxAge: 100,
    })
  );

  RecoilDebugObserver = () => {
    const snapshot = useRecoilSnapshot();
    useEffect(() => {
      for (const node of snapshot.getNodes_UNSTABLE({ isModified: true })) {
        const loadable = snapshot.getLoadable(node);
        const action = {
          type: `[recoil] ${node.key}/${loadable.state}`,
          payload: { node, loadable },
        };
        store.dispatch(action);
      }
    }, [snapshot]);
    return null;
  };
}

export { RecoilDebugObserver };

Hi just created this issue https://github.com/facebookexperimental/Recoil/issues/837 pressenting to the community some devtools I created for Recoil. Really similar to the redux devtools, so it should be easy to figure out how to use them for redux users too. A quick demo here: (see the issue for more context)

devtools

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tklepzig picture tklepzig  路  3Comments

julienJean99 picture julienJean99  路  3Comments

atanasster picture atanasster  路  3Comments

art1373 picture art1373  路  4Comments

polemius picture polemius  路  3Comments