Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLayoutEffect #27

Closed
iamjohnlong opened this issue May 11, 2019 · 3 comments
Closed

useLayoutEffect #27

iamjohnlong opened this issue May 11, 2019 · 3 comments
Labels
question Further information is requested

Comments

@iamjohnlong
Copy link

Is there an equivalent to https://reactjs.org/docs/hooks-reference.html#uselayouteffect in solid?

@ryansolid
Copy link
Member

Sort of. Solid's createEffect is closer to useLayoutEffect than it is to useEffect.

The lifecycle here is completely different. There is no lifecycle flow because the component render function only runs once. So all computations (createEffect, createMemo) run immediately and synchronous on update (or if part of a parent computation or freeze at the end of the synchronous block). What this means is Solid's effects run all synchronously and depending on dependencies and declaration order execute in that order.

So to get effects after render like useEffect I generally just defer in a promise:

createEffect(async () => {
  // could declare deps before the await too instead of in deps array
  await Promise.resolve();
  // Do Effect stuff
}, [someDep])

Technically, to get useLayoutEffect we'd want to declare an effect after render so something like this could work. Remember no Virtual DOM so elements get rendered immediately so the following works:

const SomeComp = props => {
  const view = <div>/*... view code ...*/</div>
  createEffect(() => {
    // Do Effect Stuff
  });
  return view;
}

I do think this is an interesting area to see if I could handle better with the API. useEffect equivalent could just be hiding the async nature from the consumer. Maybe a createAsyncEffect but it would require explicit dependencies. createLayoutEffect I haven't had a need for as of yet. Maybe there is something I'm missing but most things that you read from the DOM after render trigger reflow anyway to get the right value, so not sure where this fits in.

I'm definitely interested in opinions here, since as usual I have to really re-examine problems here given the differences from React.

@ryansolid ryansolid added the question Further information is requested label May 11, 2019
@iamjohnlong
Copy link
Author

@ryansolid Thanks for the explanation. Makes sense now. How does solids createEffect differ from React useEffect it terms of dependancies? createEffect deps need to be functions that return a bool?

createEffect(() => {
  // do stuff...
  // What is someDep?
}, [someDep])

Solid is awesome btw. I would suggest updating the examples to use codesandbox.io

https://codesandbox.io/s/r0q95159lm

@ryansolid
Copy link
Member

Dependencies can either be implicit via tracking of accessors during effect execution or explicit like React by adding to an optional 2nd argument. In some cases it is a lot cleaner to explicitly set dependencies. So what is someDep in my example? An accessor function that your asynchronous method depends on. What is an accessor function? It's a simple thunk to wrap the fetching of tracked value. So typically it's either a Signal like those created by createSignal and createMemo, or simply a function that wraps any state access like:

const getFirstName = () => state.firstName

The need for a function is that we need to be sure to execute the access to value under a tracked context (ie, by the effect itself) so any time we need to define a dependency outside of the execution context of the computation we need to wrap it in a function.

So let's pretend you needed to measure the size of the DOM element containing the users name after render whenever the firstName changes.

You could:

createEffect(async () => {
  // register dependency
  state.firstName;
  await Promise.resolve();
  // measure DOM element
});

Or you could just explicitly set a dependency:

createEffect(async () => {
  await Promise.resolve();
  // measure DOM element
}, [() => state.firstName])

In most cases you will be accessing the value in the effect for a reason so it isn't necessary. I just wanted to point out that that async functions return a promise when they hit that first await so no dependencies will be made after the await statement.

As for CodeSandBox. Completely I actually came across it recently and the ease at which I can get Solid running with a simple Parcel config is awesome. Not to mention syntax highlighting not being forced in parsing HTML script tags. The latest version of the Babel plugin doesn't even work in CodePen env anymore since it generates Import statements, so I do intend to most the examples to CodeSandBox or equivalent when I get the chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants