Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Ruggan posted:

Here's a first pass on how I would do this.

https://codesandbox.io/s/ovrv2ork26

Unrelated, but oh my god I hate that comment font/style/color so much :murder:

Adbot
ADBOT LOVES YOU

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!
OK so I think my issue stems from making an external call?
I'm trying (at first) to see if it's a full moon given an API, I'll later check for other celestial happenings in other child components.

once I make it a call with AXIOS then what gets returned is changed??

if I use the hardcoded this.isHardcoded() everything seems fine, but if I try to dynamically get the data instead via isMoonFull() then what returns changes?

parent:
code:
<template>
  <div id="app">
    <FullMoon @fullEmit="checkFull"></FullMoon>
    {{threatLevel}}
  </div>
</template>

<script>

import FullMoon from './components/FullMoon.vue'

export default {
  name: 'app',
  components: {
    FullMoon
  },
  data () {
    return {
      threatLevel: Number,
      isFull: Boolean
    }
  },
  methods: {

    checkFull ($event) {
      console.log('event is', $event)
      this.isFull = $event
    },
    countDumb(){
      this.threatLevel = 0;
      console.log('is it dumb?')
      console.log(this.isFull)
      if (this.isFull){
        this.threatLevel = 1;
      }

    }
  },
  mounted(){
    this.countDumb();
  }
}
</script>

child:
code:
<template>
    <div>Is this emittting?</div>
</template>
<script>
import axios from 'axios'

export default {
  name: 'FullMoon',
  data () {
    return {
        isFull: Boolean
    }
  },
  created(){
    this.isMoonFull();
    // this.isHardcoded();
 },
  methods: {    
    isHardcoded: function() {
        console.log('emitting from child')
        this.$emit('fullEmit', true)
    },
    isMoonFull: function() {
      var d = new Date();
      var date = d.getDate();
      var month = d.getMonth()+1;
      axios
      .get('http://icalendar37.net/lunar/api/?lang=en&month=' + month + '&year=2019&size=50')
      .then(response => {
        this.info = response.data;
        this.phaseName = this.info.phase[date].phaseName;
        if (this.phaseName === "Full moon") {
          this.isFull = true;
        } else {
          this.isFull = false;
        }
        console.log('going to emit ', this.isFull)
        // this.$emit('fullmoon', true)
        this.$emit('fullEmit', this.isFull)
      })
    }
  }
}
</script>
console (if running fixed]this.isEmergencyHappening()[/fixed] in created():
code:
[HMR] Waiting for update signal from WDS...
FullMoon.vue?4c0d:20 emitting from child
App.vue?234e:28 event is true
App.vue?234e:33 is it dumb?
App.vue?234e:34 true
vue.runtime.esm.js?2b0e:8423 Download the Vue Devtools extension for a better development experience:
[url]https://github.com/vuejs/vue-devtools[/url]
console (if running this.isMoonFull() in created():
code:
[HMR] Waiting for update signal from WDS...
App.vue?234e:33 is it dumb?
App.vue?234e:34 ƒ Boolean() { [native code] }
vue.runtime.esm.js?2b0e:8423 Download the Vue Devtools extension for a better development experience:
[url]https://github.com/vuejs/vue-devtools[/url]
FullMoon.vue?4c0d:37 going to emit  false
App.vue?234e:28 event is false

HaB
Jan 5, 2001

What are the odds?

The Merkinman posted:

OK so I think my issue stems from making an external call?
I'm trying (at first) to see if it's a full moon given an API, I'll later check for other celestial happenings in other child components.

once I make it a call with AXIOS then what gets returned is changed??

if I use the hardcoded this.isHardcoded() everything seems fine, but if I try to dynamically get the data instead via isMoonFull() then what returns changes?

parent:
code:
<template>
  <div id="app">
    <FullMoon @fullEmit="checkFull"></FullMoon>
    {{threatLevel}}
  </div>
</template>

<script>

import FullMoon from './components/FullMoon.vue'

export default {
  name: 'app',
  components: {
    FullMoon
  },
  data () {
    return {
      threatLevel: Number,
      isFull: Boolean
    }
  },
  methods: {

    checkFull ($event) {
      console.log('event is', $event)
      this.isFull = $event
    },
    countDumb(){
      this.threatLevel = 0;
      console.log('is it dumb?')
      console.log(this.isFull)
      if (this.isFull){
        this.threatLevel = 1;
      }

    }
  },
  mounted(){
    this.countDumb();
  }
}
</script>

child:
code:
<template>
    <div>Is this emittting?</div>
</template>
<script>
import axios from 'axios'

export default {
  name: 'FullMoon',
  data () {
    return {
        isFull: Boolean
    }
  },
  created(){
    this.isMoonFull();
    // this.isHardcoded();
 },
  methods: {    
    isHardcoded: function() {
        console.log('emitting from child')
        this.$emit('fullEmit', true)
    },
    isMoonFull: function() {
      var d = new Date();
      var date = d.getDate();
      var month = d.getMonth()+1;
      axios
      .get('http://icalendar37.net/lunar/api/?lang=en&month=' + month + '&year=2019&size=50')
      .then(response => {
        this.info = response.data;
        this.phaseName = this.info.phase[date].phaseName;
        if (this.phaseName === "Full moon") {
          this.isFull = true;
        } else {
          this.isFull = false;
        }
        console.log('going to emit ', this.isFull)
        // this.$emit('fullmoon', true)
        this.$emit('fullEmit', this.isFull)
      })
    }
  }
}
</script>

You are having execution order issues. The quick fix is: make isMoonFull async and instead of using .then, just await the result. You will have to make created() async as well so you can await the result of isMoonFull().

The order of logs on the two different versions is the evidence. With this line:
code:
App.vue?234e:34 ƒ Boolean() { [native code] }
being the real giveaway. You should be seeing a plain boolean there, like you are when it's hardcoded. Since you are executing countDumb() in mounted, the child hasn't finished doing its thing yet, tho it's probably already created (hence the api call being fired and eventually returning). Everything should be working asynchronously, tho. Having the log statements in countDumb can be misleading (as it is in this case). In other words, as long as your emit is firing, the value of isFull in the parent should be correct after the emit.

If you really need the logs in that order, then use async/await like I said, otherwise, your actual code isn't wrong, you just have log statements in an odd place which has you chasing a ghost.

smackfu
Jun 7, 2004

Paranda posted:

For a phone interview I wouldn't expect them to live code, but yeah I'm looking to hear them describe something like what you implemented, using refs, and then grabbing the height on the element. Surprisingly, a decent # of candidates can't even think of how to do it at all.

Not super surprised. You can write a lot of React, including pretty complex apps, without running into refs. Especially if you just use other peoples packages to do the complex bits.

Gildiss
Aug 24, 2010

Grimey Drawer

smackfu posted:

Not super surprised. You can write a lot of React, including pretty complex apps, without running into refs. Especially if you just use other peoples packages to do the complex bits.

Yeah I only used refs I think in one situation for an audio component.
Had no idea about that height thing but it is cool after seeing it. But yeah I have never come across that information out in the wild so wouldn't have even considered it.
Doesn't feel like as common knowledge as you think it is.

my bony fealty
Oct 1, 2008

I dunno every React project I've worked on of a decent size seems like it runs into refs sooner or later, usually for grabbing clientHeight/scrollHeight or sometimes for working with canvas. Just depends on what you're building. We like height transitions in our designs and they're useful there.

Good point about using packages as there are many "measure dom node size" things out there that people might look at instead of trying to do it with refs.

I would say that refs are a fairly important bit of React's API and you should know what they are and that they can be useful for interacting with the DOM. Like "I have read the documentation" level awareness, if you've never had reason to actually use em thats ok.

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!

HaB posted:

You are having execution order issues. The quick fix is: make isMoonFull async and instead of using .then, just await the result. You will have to make created() async as well so you can await the result of isMoonFull().

The order of logs on the two different versions is the evidence. With this line:
code:
App.vue?234e:34 ƒ Boolean() { [native code] }
being the real giveaway. You should be seeing a plain boolean there, like you are when it's hardcoded. Since you are executing countDumb() in mounted, the child hasn't finished doing its thing yet, tho it's probably already created (hence the api call being fired and eventually returning). Everything should be working asynchronously, tho. Having the log statements in countDumb can be misleading (as it is in this case). In other words, as long as your emit is firing, the value of isFull in the parent should be correct after the emit.

If you really need the logs in that order, then use async/await like I said, otherwise, your actual code isn't wrong, you just have log statements in an odd place which has you chasing a ghost.

I don't need the logs, they are there for debugging. The issue is since this.isFull in countDumb() is Boolean() { [native code] } instead of an actual Boolean with a true or false value, it's always resolving to true

I tried the async stuff you suggested, but it still isn't working, do I need to do some combo of async/await on the parent too?

HaB
Jan 5, 2001

What are the odds?

The Merkinman posted:

I don't need the logs, they are there for debugging. The issue is since this.isFull in countDumb() is Boolean() { [native code] } instead of an actual Boolean with a true or false value, it's always resolving to true

I tried the async stuff you suggested, but it still isn't working, do I need to do some combo of async/await on the parent too?

That's still an execution order problem. You are calling countDumb() in mounted(). There's no way to guarantee when the Parent has mounted that the Child component has finished pulling its data or not. Sometimes it might be, but probably not. And you can't rely on "sometimes" anyway.

Instead, you need to call countDumb() when the event is emitted. So inside of checkFull(). The reason to use an emitter is so you know the data call has completed and has data. Calling countDumb() in mounted() is checking for the existence of a thing you aren't sure is there yet.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice
Typescript question #747123:

I am using a library component that allows me to pass a component as a prop. I have a couple props of my own on said component, plus the library component adds some. How do I type this?

JavaScript code:
import { LibComponent } from 'aLibrary'

interface MyCompProps {
 // I provide these...
  blah: boolean;
  foo: number;
// these get added magically later
  x: number;
  y: number;
}

const MyComp:  React.FC<MyCompProps> = (props) => {
   const { blah, foo, x, y } = props;
   // do stuff and return a DOM element
}

// elsewhere I render this:
<LibComponent 
  labelComponent={
    <MyComp blah={true} foo={7} />
  }
/>
Done the way above, TS complains I didn't include x or y. If I omit x and y from the interface, it complains they aren't allowed props in my implementation of MyComp. So how do I handle injected props like this?

The Fool
Oct 16, 2003


Shouldn't there be a base type somewhere, x and y aren't actually being added magically. If you know what the base type is, then you should be able to just extend it:

code:
interface MyCompProps extends baseCompProps
I'm just guessing from my grand total of 3 weeks of TypeScript usage though and could be totally off base.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

The Fool posted:

Shouldn't there be a base type somewhere, x and y aren't actually being added magically. If you know what the base type is, then you should be able to just extend it:

code:
interface MyCompProps extends baseCompProps
I'm just guessing from my grand total of 3 weeks of TypeScript usage though and could be totally off base.

Forgot to say in my original post that I tried that as well and it's the same issue as the posted code. Since I don't explicitly provide values for the `baseCompProps` it yells.

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
It sounds like that lib should be using an HOC, since that's usually how adding props to a component works, but in this case, I'd probably do something like

JavaScript code:
import { LibComponent, LibProps } from 'some-lib';

interface Props {
  myNewProp: string;
}

type CombinedProps = Props & LibProps;

const MyComponent: React.FC<CombinedProps> = (props) => {
  const { myNewProp, ...rest } = props;

  return <div />
}

export default MyComponent as React.FC<Props>;
If this was an HOC, that becomes pretty simple as well

JavaScript code:
import * as React from 'react'
import { compose } from 'recompose'

import { SomeProps } from 'lib';
import { OtherProps } from 'another-lib'

interface Props {
  myNewProp: string;
}

type CombinedProps = Props & SomeProps & OtherProps;

const MyComponent: React.FC<CombinedProps> = (props) => {
  const { myNewProp, ...rest } = props;

  return <div />
}

/** 
 * first type arg is the props after the component is run through all HOCs 
 * 
 * second type arg is the base props
 */
export default compose<CombinedProps, Props>(
  HOC,
  AnotherHOC
)(MyComponent)


teen phone cutie fucked around with this message at 21:09 on May 13, 2019

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Grump posted:

It sounds like that lib should be using an HOC, since that's usually how adding props to a component works, but in this case, I'd probably do something like



Thanks for this. This library isn't typescript in and of itself, and most of the stuff provided in the DefinitelyTyped types are 'any', so in one sense, it makes it easy since MyType & any pretty much shuts up TS.... :v:

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself

Lumpy posted:

Thanks for this. This library isn't typescript in and of itself, and most of the stuff provided in the DefinitelyTyped types are 'any', so in one sense, it makes it easy since MyType & any pretty much shuts up TS.... :v:

yeah unfortunately that's one of the biggest pitfalls with TypeScript. Most of my Github open-source contributions are just me providing type definitions.

But soon or later, you're going to have to end up creating a file called somelib.d.ts and just

JavaScript code:
declare module 'some-lib' 
for when the lib doesn't have any DefinitelyTyped presence.

SurgicalOntologist
Jun 17, 2004

:can: What frameworks/packages/stacks should I look in to if we want to overlay data visualizations on top of a video playback interface?

Basically, we have a backend API that provides (the data for) animated 2D charts and a homography matrix for how these charts should be projected onto the ground plane of a video. Imagine a weathermap but on a video rather than a satellite image and you get the idea. (The transformation to 2D coordinates is trivial so we are not limited to 3D options)

I'm the backend guy, taught myself enough JavaScript to put the charts next to the video. For this next step I'm passing it off to a hypothetical new hire but I need to be better informed regardless. What technologies should I start reading up on? WebGL? D3?

Dont Touch ME
Apr 1, 2018

Have a canvas container that serves as a custom media player that manipulates the state of the video and the charts, blitting the latter into the former. Hardest part about doing that would be seeking. As long as you have a robust enough timeline definition for your charts it shouldn't be that bad, though.

WebGL is super overkill here.

You could probably do it with some stateful react.js and some css position shenanigans, but I'd just suggest going with the canvas route here.

Volguus
Mar 3, 2009
How I would do it (bear in mind that I've never done such a thing, but I do have a bit of experience with the ffmpeg API) would be to generate the video directly with the things drawn on it and just stream it to the browser. All done on the backend, no need to fluff around with the client. Ability for the client to manipulate the data that is shown (show/hide things) would be possible, but not as straightforward.

gbut
Mar 28, 2008

😤I put the UN🇺🇳 in 🎊FUN🎉


Why not just overlay in the browser?

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/timeupdate_event

Use that to drive/time the overlay. Re-rendering the video looks like an overkill to me.

SurgicalOntologist
Jun 17, 2004

gbut posted:

Why not just overlay in the browser?

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/timeupdate_event

Use that to drive/time the overlay. Re-rendering the video looks like an overkill to me.

Yeah this is how I am synchronizing the chart and the video currently. It works pretty well. Agree that re-rendering is not an option, we have lots of toggles and stuff so there are many permutations and I assume we can't render fast enough to make that smooth.

So maybe I've already done the hard part. I was concerned mostly with getting pixel-perfect alignment and making sure it acts like the chart is part of the video even if it isn't. Seems like canvas is the way to go; maybe this is easier than I thought. Thanks all.

Dont Touch ME
Apr 1, 2018

The canvas element is super robust and if you're familiar with working with graphics buffers and the math involved in low level rendering, you can optimize it to have comparable performance with WebGL. IIRC support for hardware acceleration has been added to some browsers, too.

It's very underrated and fun to work with.

gbut
Mar 28, 2008

😤I put the UN🇺🇳 in 🎊FUN🎉


Canvas, definitely, if you're aiming for pixel perfect. It's super easy to work with, or you can use something like p5.js if you want power with even more ease.

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!

You might want to check in with MrMoo. They've been posting about their work rendering stock tickers at a major trade center off and on for years. If there's something they don't know about real time data rendering (though no video involved) I'd be surprised. They have a thread in the project.log about the ticker.

MrMoo
Sep 14, 2000

WebGPU is the new upcoming graphics API du jour. Also check some other Google IO 2019 videos for some interesting tidbits, particularly with their game demo, take away is basically get everything off the renderer thread.

https://www.youtube.com/watch?v=K2JzIUIHIhc

https://www.youtube.com/watch?v=w8P5HLxcIO4

I've recently bumped my ticker work to WebGL2 courtesy of PixiJS v5. It uses more GPU memory and CPU is about all I can say about it. There's a 3 min default GPU old texture purge timer I've noted to disable. Also weird stuff like defaulting to 32 max textures but now in v5 dropping that if the hardware supports less - so you need to set a high default (?)

Some pretty demo, but I hate pages that break vertical scrolling, like the Apple Mac Pro page.


On my todo list is the following:

  • "Upgrade" things to Lit-HTML, i.e. 4th generation WebComponents.
  • Work out a mechanism of using Lit-HTML in the rendered thread but backed by business logic ES6 classes in WebWorkers.
  • OffscreenCanvas based real time graphing.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice
GraphQL server question(s):

Let's say I have this:

JavaScript code:
const typedefs = gql`
  type Query {
    getParentById(id: String!): Parent
  }

  type Parent {
    id: String!
    name: String!
    kids: [Kid]
  }
  type Kid {
    name: String!
    kidData: [DataThing]
  }
  type DataThing {
    id: String!
    value: Int!
  }
`;

const resolvers = {
  Query: {
    getParentById: getParentFromDBResolver
  }
  Parent: {
    kids: getKidsFromDBResolver
  }
  Kid: {
    kidData: fetchRemoteKidDataResolver
  }
}
Everything in there comes from a database, except kidData. That is fetched from a REST call. This is all well and good. However, let us imagine that I need to create a second "virtual" Kid for every one that exists in the DB, and that if there is kidData in those that the 'value' field undergoes a transformation in the virtual kid.

If I was getting all the data in one big DB call I could do this easily by iterating over the Kids and creating a new one and further iterating over the kidData inside and so on... but I can't do that. I'm guessing there is going to be a schema-transform in there somehow, but I'm sort of stumped on how and where (at what point / in which resolver) to access the kidData and the kids themselves to clone them and add the virtual copies. Anyone done something like this?

HaB
Jan 5, 2001

What are the odds?
Anyone have any experience with doing the following, preferably in HapiJS, since I can't find an example of someone doing it in anything close to the current version, and they had MAJOR changes as of v17 (18 is current), so any example pre v17 is basically useless since the whole api changed:

- client hits endpoint
- server hits 3rd party servers downloading various things
- server creates zipfile of downloaded things and returns it.

I am trying to use JSZip for the zipfile, and I can at least get a test one created correctly, but I can't for the life of me figure out how to get Hapi to return it, preferably streaming it as it's being built.

I cant even get the correct return with just a test file that's basically:

code:
let zip = new JSZip();
zip.file('test.txt', 'derp derp derp');

// return would go here if I could figure out which return to use.  Tried:

//return zip;
// return h.reply(zip).type('application/zip');
// (using the inert plugin):
// return h.file(zip);
No luck. Taking suggestions/advice.

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
Is anyone here really good with React refs, higher-order components, and 3rd party libs? I for one think refs are extremely confusing and was never good at wrapping my head around them, and I have yet to find a good tutorial that explains how to use refs with HOCs and 3rd party libs.

Specifically, my issue here is that I'm trying to focus input on something when a button is clicked. I'm using react-select as the input I want to focus on.

react select docs being here: https://react-select.com/home
and how to use refs with react select: https://react-select.com/components#inner-ref

So I have this parent component, let's call it Form.tsx

JavaScript code:
import React from 'react';
import { compose } from 'recompose';

const Form: React.FC<CombinedProps> = props => {
  return (
    <form className={classes.root}>
      {numberOfIngredients.map(
        (eachIteration, index) => {
         /** 
            * In a nutshell, we have 2 buttons - one to add an ingredient and one to remove an ingredient 
            * When the "add" button is clicked, we need to focus input on the last Searchbar in the list
            */
          return (
            <div className={classes.section} key={index}>
              <Searchbar
                handleChange={handleSearch}
              />
              <Button
                onClick={() => setIngredientsCount(ingredientsCount - 1)}
              >
                Remove Ingredient
              </Button>
            </div>
          );
        }
      )}
      <div className={classes.buttonWrapper}>
        <Button onClick={() => setIngredientsCount(ingredientsCount + 1)}>
          Add Ingredient
        </Button>
        <Button onClick={handleCreateRecipie}>
          Create Recipie
        </Button>
      </div>
    </form>
  );
};

export default compose<CombinedProps, RouteComponentProps>(
  withSnackbar,
  React.memo
)(Form);
Then I have my child which is Searchbar.tsx (as you can see, Searchbar is being rendered in Form.tsx)

JavaScript code:
import Select from 'react-select';
import { compose } from 'recompose';

const Searchbar: React.SFC<CombinedProps> = props => {
  return (
    <Select
      onChange={props.handleSelect}
      components={{
        /** lets us pass our own custom <input /> element */
        CustomInput: componentProps =>
          Input({ ...componentProps })
      }}
      {...props}
    />
  );
};

const Input = (props: any) => <input {...props} />

export default compose<CombinedProps, Props & SelectProps>(
  styled,
  React.memo
)(Searchbar);
How do I focus on the <SearchBar /> after the Add Ingredient button is clicked? If this isn't enough context, I'd be happy to provide more information. It's also worth noting that I've tried some methods in the React docs, but unfortunately I couldn't get everything playing nicely, such as:

https://reactjs.org/docs/hooks-reference.html#useimperativehandle
and
https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components

From what I can tell, my issue is 2 fold:

1. How do I get multiple refs with a render that using .map to render an array of <SearchBar />s?
2. How do I get that parent ref passed down to the input element?

teen phone cutie fucked around with this message at 14:41 on May 22, 2019

Paranda
Jun 9, 2003

Grump posted:

Is anyone here really good with React refs, higher-order components, and 3rd party libs? I for one think refs are extremely confusing and was never good at wrapping my head around them, and I have yet to find a good tutorial that explains how to use refs with HOCs and 3rd party libs.

Specifically, my issue here is that I'm trying to focus input on something when a button is clicked. I'm using react-select as the input I want to focus on.

react select docs being here: https://react-select.com/home
and how to use refs with react select: https://react-select.com/components#inner-ref

So I have this parent component, let's call it Form.tsx

JavaScript code:
import React from 'react';
import { compose } from 'recompose';

const Form: React.FC<CombinedProps> = props => {
  return (
    <form className={classes.root}>
      {numberOfIngredients.map(
        (eachIteration, index) => {
         /** 
            * In a nutshell, we have 2 buttons - one to add an ingredient and one to remove an ingredient 
            * When the "add" button is clicked, we need to focus input on the last Searchbar in the list
            */
          return (
            <div className={classes.section} key={index}>
              <Searchbar
                handleChange={handleSearch}
              />
              <Button
                onClick={() => setIngredientsCount(ingredientsCount - 1)}
              >
                Remove Ingredient
              </Button>
            </div>
          );
        }
      )}
      <div className={classes.buttonWrapper}>
        <Button onClick={() => setIngredientsCount(ingredientsCount + 1)}>
          Add Ingredient
        </Button>
        <Button onClick={handleCreateRecipie}>
          Create Recipie
        </Button>
      </div>
    </form>
  );
};

export default compose<CombinedProps, RouteComponentProps>(
  withSnackbar,
  React.memo
)(Form);
Then I have my child which is Searchbar.tsx (as you can see, Searchbar is being rendered in Form.tsx)

JavaScript code:
import Select from 'react-select';
import { compose } from 'recompose';

const Searchbar: React.SFC<CombinedProps> = props => {
  return (
    <Select
      onChange={props.handleSelect}
      components={{
        /** lets us pass our own custom <input /> element */
        CustomInput: componentProps =>
          Input({ ...componentProps })
      }}
      {...props}
    />
  );
};

const Input = (props: any) => <input {...props} />

export default compose<CombinedProps, Props & SelectProps>(
  styled,
  React.memo
)(Searchbar);
How do I focus on the <SearchBar /> after the Add Ingredient button is clicked? If this isn't enough context, I'd be happy to provide more information. It's also worth noting that I've tried some methods in the React docs, but unfortunately I couldn't get everything playing nicely, such as:

https://reactjs.org/docs/hooks-reference.html#useimperativehandle
and
https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components

From what I can tell, my issue is 2 fold:

1. How do I get multiple refs with a render that using .map to render an array of <SearchBar />s?
2. How do I get that parent ref passed down to the input element?

For question 1, forwarding refs (your second link) is the right idea. Currently you can't use refs the traditional way in your Form component because it's a FC. If you change it a class component you can stick a ref={this.searchInputRefs[index] = React.createRef<HTMLInputElement>()} in your code to create an array of refs, and then let your onClick do things to the desired this.searchInputRefs[index] as needed.

Another option that lets you circumvent all this Ref forwarding from Form to Search altogether is to alter your SearchBar component and add something like a "focused" or "active" prop that you can simply subscribe to for the relevant cases. You'd have to add some protection around preventing the SearchBar from stealing focus but this makes whatever internal implementation of autofocus primary to your SearchBar component that deals with inputs, and changes your Form's responsibility simply to deciding which SearchBar is the one should be the one to get the focused prop. Meanwhile you let SearchBar handle what exactly it means to focus on either Input or Select or Dropdown or whatever it is you wanted. I generally prefer to do this with complex Inputs since it helps me reason out the interactions between the components more easily in my head.

For question 2, connecting SearchBar ref to Input, since you're passing your own custom Input component into react-select, you'd pass the ref down to the innerRef property based on the documentation you linked (https://react-select.com/props#input) and then hook that up to the ref in your component's HTML input element.

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself

Paranda posted:

For question 1, forwarding refs (your second link) is the right idea. Currently you can't use refs the traditional way in your Form component because it's a FC. If you change it a class component you can stick a ref={this.searchInputRefs[index] = React.createRef<HTMLInputElement>()} in your code to create an array of refs, and then let your onClick do things to the desired this.searchInputRefs[index] as needed.

Another option that lets you circumvent all this Ref forwarding from Form to Search altogether is to alter your SearchBar component and add something like a "focused" or "active" prop that you can simply subscribe to for the relevant cases. You'd have to add some protection around preventing the SearchBar from stealing focus but this makes whatever internal implementation of autofocus primary to your SearchBar component that deals with inputs, and changes your Form's responsibility simply to deciding which SearchBar is the one should be the one to get the focused prop. Meanwhile you let SearchBar handle what exactly it means to focus on either Input or Select or Dropdown or whatever it is you wanted. I generally prefer to do this with complex Inputs since it helps me reason out the interactions between the components more easily in my head.

For question 2, connecting SearchBar ref to Input, since you're passing your own custom Input component into react-select, you'd pass the ref down to the innerRef property based on the documentation you linked (https://react-select.com/props#input) and then hook that up to the ref in your component's HTML input element.

Hey that makes a lot of sense thanks. What about useRef. This allows me to now use refs in functional components, right?

I imagine if I went the route of using an "focused" prop on my Searchbar, I'd need to set that state when the "add ingredient" button is clicked? And then what exactly would my Searchbar component be doing at that point? Calling ref.current.focus() on the custom input? I'm confused as to where exactly I'd be calling the focus().

Dominoes
Sep 20, 2007

Is it still good prac to use triple eq, assuming Typescript?

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself

Dominoes posted:

Is it still good prac to use triple eq, assuming Typescript?

yeah never use double equal. There's no good reason to not use triple.

Dominoes
Sep 20, 2007

It'd be nice to have a Tsconfig var that converts dbl to trpl.

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
There's a tslint rule you could throw an error on.

smackfu
Jun 7, 2004

After saying I never use refs in React two weeks ago, I’ve used them for two different things this week. For interacting with the video tag, and for setting focus in a form on errors. Very handy when you need it.

Paranda
Jun 9, 2003

Grump posted:

Hey that makes a lot of sense thanks. What about useRef. This allows me to now use refs in functional components, right?

I imagine if I went the route of using an "focused" prop on my Searchbar, I'd need to set that state when the "add ingredient" button is clicked? And then what exactly would my Searchbar component be doing at that point? Calling ref.current.focus() on the custom input? I'm confused as to where exactly I'd be calling the focus().
Yeah. It's a bit of a pain in the rear end to wrangle two layers of refs through FCs but I wrote a quick example of how you would do this generally based on your example https://codesandbox.io/s/refs-example-1fc4x

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself

Paranda posted:

Yeah. It's a bit of a pain in the rear end to wrangle two layers of refs through FCs but I wrote a quick example of how you would do this generally based on your example https://codesandbox.io/s/refs-example-1fc4x

Thanks for this. Unfortunately, my button is going under the array of search bar elements so I would probably need to dispatch some custom event and then add an event listener to the last searchbar in the list. I actually tried this tonight, but it ended up not working since the event listener was being dispatched in the onClick of the button.

And the problem there is that the DOM was being repainted AFTER the event was dispatched, making it so the second to last searchbar was being focused. I'm really starting to pull my hair out here. I'll try to post an example of my could different approaches tomorrow.

I've also found out that using the react-select input doesn't take a ref. Instead it provides a callback function that gives you access to the underlying input element.

so like:

JavaScript code:

import { RSInput } from 'react-select'
 
    <Select
      inputValue={props.query}
      options={filteredOptions as any}
      onChange={handleSelect}
      components={{
	/** element here in the callback is the input DOM element, so I could just call element.focus if I wanted, but now I need to pass it up to the parent */
        Input: inputProps => <RSInput {...inputProps} innerRef={(element) => element} />
      }}
      {...props}
  />

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
Solved my issue. Here's how:


https://codesandbox.io/embed/nameless-leftpad-o3zwl

But also I'm running into weird issues now when I start typing the input loses focus and focuses on the body somehow???? wtf? I've got a SO question on what exactly is going wrong for me with this one:

https://stackoverflow.com/questions/56285886/react-select-custom-input-losing-focus

I'm assuming this is most likely me not understanding something about how React works, rather than this being a react-select bug.


https://codesandbox.io/s/reactselect3575-fixed-8u04m

e: I now think refs are cool and good.

wooohooo!

teen phone cutie fucked around with this message at 19:09 on May 24, 2019

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
Ok sorry I have another question.

What's the appropriate way to write debounce logic in React functional components? This works for me, but is there another approach that's more graceful?

JavaScript code:
import React from 'react'
import { debounce } from 'throttle-debounce';

let debouncedFetch: any;

const Searchbar = props => {

  const [query, setQuery] = React.useState<string>('');
  const [isFetching, setFetching] = React.useState<boolean>(false);
  const [data, setData] = React.useState([])

  const asyncRequest = (value: string) => {
    return props.handleInputChange(value)
      .then(response => {
        setFetching(false);
        setData(response);
      })
      .catch(e => {
        setFetching(false);
        setData([])
      })
  }

  React.useEffect(() => {
    debouncedFetch = debounce(750, false, asyncRequest);
  }, [])


  const _handleInputChange = (value: string, action: any) => {
    setQuery(value);
    if (typeof debouncedFetch === 'function') {
      setFetching(true)
      debouncedFetch(value);
    }
  }

  return (
    <SelectField
      inputValue={query}
      dropDownOptions={data}
      onInputChange={_handleInputChange}
      isLoading={isFetching}
      {...props}
    />
  );
};

uncle blog
Nov 18, 2012

We have a frameset of three frames where the content in the child frames will change when the user clicks an a-tag with a href and a target specifying the frame to load the content in. We want to replace the frames with divs. What's the easiest way to get the same dynamic functionality from the current frameset with divs?

RC Cola
Aug 1, 2011

Dovie'andi se tovya sagain
If I had to choose one to learn, should I learn Angular or React?

Adbot
ADBOT LOVES YOU

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself

RC Cola posted:

If I had to choose one to learn, should I learn Angular or React?

Spend some time on job boards, figure out which one is more in-demand in your city, and learn that one.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply