Giter Site home page Giter Site logo

Rules for property accesses about hooks.macro HOT 9 OPEN

yuchi avatar yuchi commented on August 17, 2024
Rules for property accesses

from hooks.macro.

Comments (9)

adrianhelvik avatar adrianhelvik commented on August 17, 2024

Idea: When accessing .current on a variable, it must be explicitly labelled or inferred to either be a ref or a non-ref. Assignment to useRef would automatically label it as a ref, as would wrapping it in the new macros markRef and markNonRef.

Triggers warning:

function App({ myRef /* is ref: unknown */ }) {
  useAutoEffect(() => {
    myRef.current
  })
  return null
}

Does not trigger warning:

function App({ myRef }) {
  markRef(myRef) // is ref: true
  useAutoEffect(() => {
    myRef.current
  })
  return null
}
function App({ myRef }) {
  markNonRef(myRef) // is ref: false
  useAutoEffect(() => {
    myRef.current
  })
  return null
}
function App() {
  const myRef = useRef() // is ref: true
  useAutoEffect(() => {
    myRef.current
  })
  return null
}
function App({ myRef /* is ref: unknown */ }) {
  const { current } = myRef
  useAutoEffect(() => {
    current
  })
  return null
}

from hooks.macro.

adrianhelvik avatar adrianhelvik commented on August 17, 2024

If the default behavior is to add the object to dependencies and show a warning, it would probably not break a lot of code.

from hooks.macro.

adrianhelvik avatar adrianhelvik commented on August 17, 2024

The algorithm

  • If .current is accessed in the scope or child scope of an auto hook
    • Find its highest parent (foo.bar.current -> foo)
    • Determine status of highest parent.
      • If maybeRef, throw error.
      • If isRef, add top parent to dependencies.
      • If isNonRef, add property access to dependencies.

Determine status

  • If defined in hook: nonRef
  • Go to component function scope
    • If defined by React.useRef: isRef
    • If defined by React.use*: isNonRef
    • If called with markRef in component function scope: isRef
    • If called with markNonRef in component function scope: isNonRef
  • Otherwise: maybeRef

Error message

Could not determine if ${expression} was ref or not.

Include `markRef(${topParent})` or `markNonRef(${topParent})`
in the function body to specify whether `${topParent}.*.current`
or is a React ref.

markRef/markNonRef

  • For each argument:
    • Assert that it's an identifier and that it is in scope
  • Remove call expression

from hooks.macro.

neoncube2 avatar neoncube2 commented on August 17, 2024

Is it possible to have useAutoMemo() generate a variable with a munged name and then use that variable when memoizing?

e.g.

function MyComponent({ config }) {
  const __asdfanasdfjl__ = config.value;
  return useMemo(() => __asdfanasdfjl__ * 2, [__asdfanasdfjl__]);
}

from hooks.macro.

yuchi avatar yuchi commented on August 17, 2024

@neoncube2 yeah that is the plan, the problem is that accessing a property is not pure/idempotent (think property getters) and some ordering may need to be respected.

@adrianhelvik your approach is actually very clean! I’ll look into it! (Sorry for the huge delay!)

from hooks.macro.

adrianhelvik avatar adrianhelvik commented on August 17, 2024

No worries. That's great news! 🙂

from hooks.macro.

neoncube2 avatar neoncube2 commented on August 17, 2024

Thanks, @yuchi. I wonder if the ordering really needs to be respected, though? My understanding is that render() is already supposed to be pure, so it seems like we should be able to access properties as many times as we like without side effects 🙂

from hooks.macro.

yuchi avatar yuchi commented on August 17, 2024

@neoncube2 Yes, render functions are pure, but callbacks and effect callbacks can (and usually indeed are) impure.

from hooks.macro.

adrianhelvik avatar adrianhelvik commented on August 17, 2024

Some important things to consider is conditionals, this-context and impure getters. This contrived example:

const [config, configure] = useState()

const ref = useAutoCallback(element => {
  configure({
    actions: {
      click() { element.click() }
    }
  })
})

useAutoEffect(() => {
  if (!element) return
  config.actions.click()
})

return <button ref={ref}>Click me!</button>
(Train of thought)

Would break if transpiled into:

var _click = config.actions.click

useEffect(() => {
  if (!element) return
  _click()
}, [_click])

An alternative would be to transpile into:

var _click = config?.actions?.click

useEffect(() => {
  if (!element) return
  _click()
}, [_click])

But that would change the this context, if the ref looked like this for example:

const ref = useAutoCallback(element => {
  configure({
    element,
    click() { this.element.click() }
  })
})

So the original input...

Should leave us with something like:

// ...

var _click = config?.actions?.click
useEffect(() => {
  if (!element) return
  _click.call(config.actions)
}, [element, _click])

// ...

Edit: Then again, I don't think supporting impure getters should be the highest priority as it complicates the implementation for minimal gain. Without support for impure getters, there will be no need to handle this-context.

// ...

useEffect(() => {
  if (!element) return
  config.actions.click()
}, [element, config?.actions?.click])

// ...

from hooks.macro.

Related Issues (16)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.