Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

feature(website): Toggle Tree Style #2563

Merged
merged 11 commits into from
May 11, 2022
Merged

Conversation

NicholasLYang
Copy link
Contributor

@NicholasLYang NicholasLYang commented May 9, 2022

Summary

As some have pointed out, the JSON view is not optimal for some situations. This allows users to toggle between the text and JSON view.

Test Plan

Screen Shot 2022-05-11 at 1 14 29 PM

Screen Shot 2022-05-11 at 1 14 33 PM

Screen Shot 2022-05-11 at 1 15 10 PM

Screen Shot 2022-05-11 at 1 15 15 PM

@NicholasLYang NicholasLYang temporarily deployed to aws May 9, 2022 17:46 Inactive
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented May 9, 2022

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: bd71c68
Status: ✅  Deploy successful!
Preview URL: https://63ecfd24.tools-8rn.pages.dev

View logs

@NicholasLYang NicholasLYang temporarily deployed to aws May 9, 2022 18:12 Inactive
@github-actions
Copy link

github-actions bot commented May 9, 2022

@NicholasLYang NicholasLYang temporarily deployed to aws May 9, 2022 19:55 Inactive
@IWANABETHATGUY
Copy link
Contributor

Could you add some screenshots or videos about the change of this pr?

@IWANABETHATGUY
Copy link
Contributor

Could you add some screenshots or videos about the change of this pr?

Sorry, I didn't see the preview playground

@MichaReiser
Copy link
Contributor

Could you add some screenshots or videos about the change of this pr?

Sorry, I didn't see the preview playground

I would still find it useful to have a proper test summary because it safes me time as a reviewer:

  • No need to open the playground and go searching for the new option
  • It helps me understand how you tested your change. Thish enables me to make suggestion in case I'm aware of something that needs testing too.
  • It acts as documentation for the future. Assume Rome continues to grow and some PR that you haven't been aware of breaks one of your features. Proper test cases are useful in this scenario because it makes it easier for you do understand what changed and indeed, check if what you're looking into was tested or should have been tested.

Copy link
Contributor

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label seems to be missing on mobile

image

<TreeView tree={cst} />
<TreeView
treeStyle={treeStyle}
setTreeStyle={setTreeStyle}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Events are commonly called onTreeStyleChanged to align it with HTML event handlers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehh I'd actually push back on this. I don't think it's more declarative to use the on-prefix, as these functions aren't running when the tree style changes, they're making the tree style change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason why I would change it is because TreeView now makes very specific assumption in what context its used. The signature implies that setTreeStyle must set the tree style. It kind of takes the choice from the parent what it want's to do in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused, how does TreeView make an assumption about the context in which it's used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name setTreeStyle implies that the using component has to set the treeStyle just by how it's named. onTreeStyleChanged on the other hand doesn't make any implication what the parent does in that case. It's like... here, this thing happened... do what ever you like, I don't care. Whereas setTreeStyle reads more like... Hey, set the tree state.

website/playground/src/TreeStyleSelect.tsx Outdated Show resolved Hide resolved
website/playground/src/TreeView.tsx Outdated Show resolved Hide resolved
@@ -21,6 +22,8 @@ export interface PlaygroundState {
setIsTypeScript: (isTypeScript: boolean) => void;
isJsx: boolean;
setIsJsx: (isJsx: boolean) => void;
treeStyle: TreeStyle;
setTreeStyle: Dispatch<SetStateAction<TreeStyle>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Change to plain function

@@ -98,6 +103,8 @@ export function usePlaygroundState(): PlaygroundState {
setIsJsx,
sourceType,
setSourceType,
treeStyle,
setTreeStyle,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is becoming hard to navigate. Separating this into a single state object with a reducer that allows changing single fields would remove the fields by about 50%.

Another alternative is to store the values in a context and having a provider + consumer hook.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah..I was considering gasp adding Redux because we're reaching the point where we have enough state such that Redux might be worth it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to add Redux just for that. A simple useContext should do to have shared state or change it to useDispatcher.

@NicholasLYang NicholasLYang temporarily deployed to aws May 10, 2022 15:32 Inactive
interface Props { settings: PlaygroundSettings }
interface Props {
settings: PlaygroundSettings;
setPlaygroundState: Dispatch<SetStateAction<PlaygroundState>>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichaReiser I'm using the complicated type signature here because I'm making use of the setPlaygroundState(state => ...) pattern

(searchParams.get("sourceType") as SourceType) ?? SourceType.Module,
);
const [treeStyle, setTreeStyle] = useState(TreeStyle.Json);
const [playgroundState, setPlaygroundState] = useState({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to move this into a lambda so that the initialize code only runs for the first render:

const [..] = useState(() => ({....}))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah my bad, forgot to do that

Comment on lines +76 to +93
export function createSetter(
setPlaygroundState: Dispatch<SetStateAction<PlaygroundState>>,
field: keyof PlaygroundState,
) {
return function (param: PlaygroundState[typeof field]) {
setPlaygroundState((state) => ({ ...state, [field]: param }));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you're trying to replicate is useReducer

The idea is to have one action for each field.

Overall, what you're trying to do here feels complicated with passing down the setPlaygroundState and then having a createSetter. For someone to understand the code they must first understand what setPlaygroundState is, then what createSetter does` for something that's otherwise relatively simple.

I think what you want here is useContext which helps you avoid the prop drilling (passing down many props multiple level-deep).

The provider doesn't need to accept any props because it initializes the state from the URL params.

They consumer can then expose the state + a method to change a single field

const [{ code }, dispatchPlaygroundAction] = usePlaygroundState();

dispatchPlaygroundAction("change_code", code); 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehhh. I just did the useReducer refactor with useContext. It gets very hairy. First, useContext is quite annoying in that you can't call createContext inside a component, so it doesn't play well with other hooks like useReducer. You have to initialize the context values to undefined/null, or initialize them in the context, but then re-initialize them in the reducer as well. If you initialize them to undefined/null, TypeScript gets very annoyed (understandably) about you using potentially undefined variables.

With actions, they are more explicit, but I could also easily make this more explicit by not using createSetter and just using setter functions explicitly. In my experience useReducer makes more sense when you need to do actions more complicated than set, i.e. actions where you change multiple parts of the state at once and need the abstraction of an action over just a setter. In this case while we have a lot of state, we're almost always just setting one field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having done this refactor just now, I have to say, it makes me a little more pro-Redux. With the starter kit, Redux is not much more overhead than useReducer + useContext and it avoids all of these nasty undefined/null issues.

@MichaReiser
Copy link
Contributor

We can do the refactor changes as part of another PR. Please update your test plan with a screenshot for Mobile/Desktop.

@NicholasLYang NicholasLYang temporarily deployed to aws May 11, 2022 21:41 Inactive
@NicholasLYang NicholasLYang temporarily deployed to aws May 11, 2022 21:41 Inactive
@NicholasLYang NicholasLYang merged commit 3d5b0f0 into main May 11, 2022
@NicholasLYang NicholasLYang deleted the feature/toggle_tree_view branch May 11, 2022 21:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants