Skip to content

Sync ref types in JSX & Context#364

Merged
Mortaro merged 1 commit intonullstack:unstable-nextfrom
GuiDevloper:types-improvements
Jun 28, 2023
Merged

Sync ref types in JSX & Context#364
Mortaro merged 1 commit intonullstack:unstable-nextfrom
GuiDevloper:types-improvements

Conversation

@GuiDevloper
Copy link
Copy Markdown
Member

Highlights:

  • The ref injected in ClientContext will always be a {object: ..., property: ...} (except when typed/passed as prop, e.g. NullstackClientContext<{ ref: string }>)

Here a extensive/ostensive list of possible cases working all together after this change and #360:

import Nullstack, { NullstackClientContext } from 'nullstack'
const PLACEHOLDER_AUDIO =
  'http://commondatastorage.googleapis.com/codeskulptor-assets/Collision8-Bit.ogg'

class ChildComplexRef extends Nullstack {

  element: HTMLAudioElement = null
  hydrate({ ref }: NullstackClientContext) {
    // ref === { object: ..., property: ... }
    ref.object[ref.property] = this.element // sets parent
    this.element.innerHTML = 'a text to parent' // also sets parent
  }

  render() {
    return <audio ref={this.element} src={PLACEHOLDER_AUDIO} />
  }

}

const constComplexRef = {
  object: { fn: null as HTMLAudioElement },
  property: 'fn' as const,
}

class ComplexRef extends Nullstack {

  complexRef: HTMLAudioElement
  playAudioRef() {
    this.complexRef.play() // plays rightly typed
    constComplexRef.object[constComplexRef.property].play() // also plays rightly typed
  }

  render() {
    return (
      <>
        <ChildComplexRef ref={this.complexRef} />
        <ChildComplexRef ref={constComplexRef} />
        <button onclick={this.playAudioRef}>Play Child's Ref</button>
      </>
    )
  }

}

class SimpleRef extends Nullstack {

  simpleAudioRef: HTMLAudioElement
  runsAfterShowing() {
    console.log('audio tag in the house!')
  }

  render({ ref }: NullstackClientContext) {
    return (
      <>
        <audio ref={this.simpleAudioRef} TS="right!" src={PLACEHOLDER_AUDIO} />
        <audio ref={this.runsAfterShowing} TS="right!" />
        <audio ref={ref} TS="right!" />
        <button onclick={() => this.simpleAudioRef.play()}>
          Play this Ref
        </button>
      </>
    )
  }

}

function PropRef({ ref }: Partial<NullstackClientContext<{ ref: string }>>) {
  return ref // ref === string
}

class Refs extends Nullstack {

  render() {
    return (
      <>
        <SimpleRef />
        <ComplexRef />

        <PropRef ref="a random string prop" />
        <PropRef ref={['TS Error: it should be an string, user!']} />
        <PropRef ref={() => 'TS Error: you know what a string prop means?'} />

        {/**
        // Uncomment this to break render
        // because a Proxy Ref function is not (() => void | function() {})
        <audio
          ref={() => {
            console.log("Error in Nullstack, where're you going at though??")
          }}
        />
        **/}
      </>
    )
  }

}

export default Refs

Also:

  • In the past NullstackClientContext['ref'] were wrongly typed with object | function, but it could be they two at same time, being better typed with Intersection: object & function.. but, with this PR this goes to another level and the function type always belonged to Attributes['ref'] as stated by 📝 feat: added element ref type #360 🚀
  • In the past I myself typed ElementTagHTMLAttributes with AllHTMLAttributes<'div'>, but the Element argument always needed to be an HTMLElement, being the right: AllHTMLAttributes<HTMLDivElement>

@Mortaro Mortaro merged commit 4105ec6 into nullstack:unstable-next Jun 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants