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
Kekekela
Oct 28, 2004
Finally got around to using VSCode and am pleasantly amazed. I expected a more Atom-like experience, but VSCode is about a billion times more responsive.

Adbot
ADBOT LOVES YOU

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Grump posted:

Yeah I'm only using a bit of Jquery to handle a form submission and pushing the input of a form to an array. And then I'm importing that script to the form component.

My only issue I've been having is that I'm hiding/showing form based on state and I'm having problems getting the script to run correctly after the button to render the form is clicked. I understand that the script isn't running because it can't find #addform on the page because <Form/> hasn't been rendered yet, but I don't get why it won't work after <Form/> has been rendered.


Don't mix jQuery and React unless you really, really, really understand how React handles DOM manipulation. As Helicity said, there's absolutely no reason for you to be using jQuery for this, so don't.

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
yeah. I'm definitely aware that I don't really need JQuery. It's bad practice, and I was just being lazy. I'll definitely re-write that part.

Lumpy posted:

Don't mix jQuery and React unless you really, really, really understand how React handles DOM manipulation. As Helicity said, there's absolutely no reason for you to be using jQuery for this, so don't.

Okay. I think there was just a misunderstanding because I was following early advice provided by you and piratepilates.

piratepilates posted:

edit: Also since I can be more specific to what you want to do, for your form component all you need to do is have a method on your component for when you want to create the person object (I'm going to assume it's something like "user pressing the enter key"). In that method just create the new person instance as if this was regular plain vanilla JS (because it is!), and push that instance to your array that is holding people (I'm guessing you want to pass the array in to the component as a prop).

Lumpy posted:

To reiterate what piratepilates said in other terms: React *shouldn't* have that stuff in there. React renders what you tell it to, that's it. Obviously a simplification, but yeah, React is the V. Your model can be whatever you want (Redux, Angular, plain old JS you write yourself, an external API / Firebase) and you use actions to let the view inform the model (or controller, or whatever) that something happened in your app. Your code is then responsible for passing new state to your view when something changes outside of it (an API request completed or failed, etc.)

In my React apps, React is about 10-20% of the code. You can build a functional, unit tested Redux app that's "feature complete" before you even npm -i react.

I guess I'm just confused about how you can push the new Person instance to an array in React, rather than just creating a method inside my Form component and writing it in vanilla Javascript.

But I'm assuming the short answer is just read up on Redux?

Also, thanks for bearing with me, everybody! I realize that I'm being a pain in the rear end. This is just super frustrating for me to learn this library.

Kekekela
Oct 28, 2004

Grump posted:

yeah. I'm definitely aware that I don't really need JQuery. It's bad practice, and I was just being lazy. I'll definitely re-write that part.


Okay. I think there was just a misunderstanding because I was following early advice provided by you and piratepilates.



I guess I'm just confused about how you can push the new Person instance to an array in React, rather than just creating a method inside my Form component and writing it in vanilla Javascript.

But I'm assuming the short answer is just read up on Redux?

Also, thanks for bearing with me, everybody! I realize that I'm being a pain in the rear end. This is just super frustrating for me to learn this library.

If I'm understanding the discussion correctly, you want to pass in an addPerson function. In redux that function would be dispatching actions to your reducer. The reducer would then update the redux store's state. When the state updates, connected components get updated automatically.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Grump posted:


I guess I'm just confused about how you can push the new Person instance to an array in React, rather than just creating a method inside my Form component and writing it in vanilla Javascript.

But I'm assuming the short answer is just read up on Redux?

Also, thanks for bearing with me, everybody! I realize that I'm being a pain in the rear end. This is just super frustrating for me to learn this library.

You aren't being a PITA, you are learning, so good for you!

As for how to make Persons and put them in an array....

You should have somewhere in your application state a collection to hold them. Let's do the absolute simplest thing and make your whole app state:

JavaScript code:
{ people: [] }
What does your app do? Let us say it does the simplest thing possible and only allows users to add a new Person. So, we need an action to do that:

JavaScript code:
const ADD_PERSON = 'ADD_PERSON';
const addPerson = ( personData ) => ({
    // if you really need to construct a Person object, do that here, I'm just going to
    // assuming having an plain JS object is fine...
    type: ADD_PERSON,
    personData,
});
So now I can do something like:

JavaScript code:
dispatch( addPerson({  firstName: 'Lumpy',   lastName: 'Pingu', }) );
In my reducer, I handle that action:

code:
const reducer = (state, action) => {
   switch (action.type) { 
      case ADD_PERSON:
          return {
              ...state,
              state.people.concat( action.personData ),
          };
      default:
          return state;
   }
};
So whenever I dispatch that action, from wherever it happens to be dispatched in my app, I get that person into the app state. So your "Form" component would get the dispatch-able addPerson action creator passed to it (probably via mapDispatchToProps) and it would dispatch the action when the "submit" button is clicked. You can access the inputs in a number of ways (refs, for example) to get the values in them, or make them controlled child components and store the values as local state depending on your needs.

Lumpy fucked around with this message at 19:33 on Feb 6, 2017

geeves
Sep 16, 2004

Helicity posted:

Sounds like you've never experienced the bliss of working in a giant SPA that is jQuery BBQ wrapped by Angular, with a dash of React thrown in (using both Flux and Redux of course).

If you had said Angular dumpster fire, then I would wonder if you were one of my coworkers.

Pollyanna
Mar 5, 2005

Milk's on them.


I don't know what you guys are talking about, Redux is really easy:

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I
If you want to make handling forms with react/redux a little easier spend ten minutes shouting "HUH?!" at a redux-form tutorial and then another five minutes going "oh ok".

luchadornado
Oct 7, 2004

A boombox is not a toy!

Grump posted:

But I'm assuming the short answer is just read up on Redux?

Also, thanks for bearing with me, everybody! I realize that I'm being a pain in the rear end. This is just super frustrating for me to learn this library.

Short answer IMO is read up on Event Sourcing for an afternoon, and then Redux.

My experience with less senior devs is that the afternoon you spend learning about Event Sourcing saves you tons of time down the road, and you also learn a pattern that's useful outside of web dev. In Event Sourcing you have a store that is your source of truth and holds your data. In React, this is called your state. React doesn't provide an out of the box way to manage your state once you move beyond Hello World. This is where Redux comes in.

A quick history of state management in React: Facebook made Flux to manage your state, and it was a complicated over-engineered mess that was a PITA to use. Most people that liked React wrote their own state management code that was essentially Event Sourcing, but without good thought into how well it scaled and the importance of immutability. Around the same time, one smart guy wrote Elm as his thesis and incorporated Event Sourcing. Dan Abramov liked React and saw the elegance in Elm as a solution to state management, and that's how Redux was born. There are other contenders like MobX, but Redux is in a fairly good place, has a huge community, and is primarily hindered by not having good examples and letting people shoot themselves in the foot, not because it's bad or anything. The documentation just got a huge update, and once you learn the principles that Redux is embracing, you're far less likely to shoot yourself in the foot.

Don't worry about asking questions or being a PITA. JS ecosystem is moving super fast right now, and it's suffering from a course set by a handful of first movers that were clever but probably not true "craftsmen" in the Pragmatic Programmer sense. So it sucks for new people. Consequently, more senior people get better by verbalizing their thoughts and teaching others, so it's a win-win.

geeves posted:

If you had said Angular dumpster fire, then I would wonder if you were one of my coworkers.

We do use that term sometimes, but I don't think we hate the Angular part nearly as much as the rest.

teen phone cutie
Jun 18, 2012

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

Lumpy posted:

As for how to make Persons and put them in an array....

Cool. After staring at this post and the documentation all day, it's starting to make sense.


Helicity posted:

Short answer IMO is read up on Event Sourcing for an afternoon, and then Redux.

Definitely gonna do some more research tomorrow. Thanks for taking the time to write this and your other post.

teen phone cutie fucked around with this message at 02:49 on Feb 7, 2017

luchadornado
Oct 7, 2004

A boombox is not a toy!

Pollyanna posted:

I don't know what you guys are talking about, Redux is really easy:

You're joking, and that diagram could use a little cleaning up to be more useful, but it's a great idea to design your state/actions/reducers/selectors up front.

an skeleton
Apr 23, 2012

scowls @ u
Hi, I was wondering if anyone has a resource, blog, site, etc. that aggregates / talks about / otherwise lists research that is relevant to UX/UI in software engineering / Human-computer Interaction.

edit: anything vaguely similar to this description would also be helpful. im not sure exactly what im looking for other than stuff that could help facilitate data-driven approaches/understanding of UX/UI engineering

an skeleton fucked around with this message at 08:15 on Feb 7, 2017

geeves
Sep 16, 2004

Helicity posted:

We do use that term sometimes, but I don't think we hate the Angular part nearly as much as the rest.

None of us really do, either, except the two devs that implemented it basically tied our app forever to angular 1.x with what they did. It isn't so much a coding horror as it is a coding war crime.

Everything new that we do is outside of that structure thankfully. But there is still plenty of work to be done within existing modules.

Kekekela
Oct 28, 2004

an skeleton posted:

Hi, I was wondering if anyone has a resource, blog, site, etc. that aggregates / talks about / otherwise lists research that is relevant to UX/UI in software engineering / Human-computer Interaction.

edit: anything vaguely similar to this description would also be helpful. im not sure exactly what im looking for other than stuff that could help facilitate data-driven approaches/understanding of UX/UI engineering

Maybe the invision ecourses? https://www.invisionapp.com/ecourses/principles-of-ux-design

Kekekela
Oct 28, 2004

Kekekela posted:

Finally got around to using VSCode and am pleasantly amazed. I expected a more Atom-like experience, but VSCode is about a billion times more responsive.

Day 2: Now crying tears of joy and sending screenshots to co-workers with every new awesome feature I uncover

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Pollyanna posted:

I don't know what you guys are talking about, Redux is really easy:



That diagram could use someone going over it a few more times, but...it seems pretty straightforward? At least when it comes to forms.

Really, it's surprising how complex forms actually are no matter the technology you're using, and Redux is one of the ways that make them simpler to handle.

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I
I had a dream last night about setting up a webpack config.

I don't think I want to move into this industry anymore.

teen phone cutie
Jun 18, 2012

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

I ended up doing similar in React, without the actual need for Redux. I don't know what this may look like to you guys, but it seems to work. This will effectively make my form data into an object, put that object into an array (which is the state of the app), and print it out as an entry. I may be making my life harder when I go to edit and delete these entries, but I guess we'll see.

When a new contact gets added, the state ends up looking like this

state{
people: [{
fname: jerry
lname: jones
email: asdf@gmail.com
address: 123 Fake St
phone: 1231231234
},
{
fname: ken
lname: lewis
email: aaaaaa@gmail.com
address: 4324 Faker St
phone: 5436541232
}]
}

Redux was just going over my head too much. It's so confusing. I think I have to start with smaller exercises to grasp it better.

So I now have three components: Entries.js (which will list each new person), Form.js (simply holds the form) and Parent.js (which holds the state to be changed and the function that runs when the form is submitted)

Parent.js

code:
class Parent extends Component {
    constructor(props, context) {
        super(props, context);
        //set state to an empty array
        this.state = {
            people: []
        };
    }
    handleSubmit = e => {
        e.preventDefault(); //prevent form from refreshing the page
        var myForm = document.getElementById('addform');
        let data = new FormData(myForm); //grabs all the input data from the form
        var eachPerson = {}; //eachPerson will concatonate with this.state, so it will end up being an array of objects
        for (let [key,
            val]of data.entries()) {
            eachPerson[key] = val;
        } //object will end up looking like this {fname: "Joe"}
        var people = [
            ...this.state.people,
            eachPerson
        ] //add the new object to the people array
        this.setState({people});
        document
            .getElementById("addform")
            .reset(); //reset the input fields onsubmit
    }
    render() {
        return (
            <div>
                //form will run handleSubmit when submitted
                <Form onClick={this.handleSubmit}/>
                //the state of parent is passed to entries as a prop
                <Entries people={this.state.people}/>
            </div>
        )
    }
}
Form.js

code:
class Form extends Component {
    render() {
        return (
            <form id="addform" name="addform" onSubmit={this.props.onClick}>
                <input type="text" name="fname" placeholder="First name" required />
                <input type="text" name="lname" placeholder="Last name" required />
                <input type="email" name="email" placeholder="email" required />
                <input type="input" name="address" placeholder="address" required />
                <input type="tel" name="phone" placeholder="phone number" required />
                <input type="submit" id="submitbtn" value="Submit"/>
                <button type="button" id="closebtn" onClick={this.props.onClick}>
                    Close</button>
            </form>
        );
    }
}
Entries.js

code:
class Entries extends Component {
  render() {
    // Parent'js state (an array named people) was passed to entries as a prop //
    // map over each object in the people array
    let peopleData = this
      .props
      .people
      .map((object, index) => {
        // return each property in each object
        return (
          <div key={index}>
            <h1>{object.fname} {object.lname}</h1>
            <p>{object.address}</p>
            <p>{object.email}</p>
            <p>{object.phone}</p>
          </div>
        )
      });
    //display the results of peopleData
    return (
      <div>{peopleData}</div>
    )
  }
}

teen phone cutie fucked around with this message at 21:55 on Feb 8, 2017

piratepilates
Mar 28, 2004

So I will learn to live with it. Because I can live with it. I can live with it.



Grump posted:

I ended up doing similar in React, without the actual need for Redux. I don't know what this may look like to you guys, but it seems to work. This will effectively make my form data into an object, put that object into an array (which is the state of the app), and print it out as an entry. I may be making my life harder when I go to edit and delete these entries, but I guess we'll see.

When a new contact gets added, the state ends up looking like this

state{
people: [{
fname: jerry
lname: jones
email: asdf@gmail.com
address: 123 Fake St
phone: 1231231234
},
{
fname: ken
lname: lewis
email: aaaaaa@gmail.com
address: 4324 Faker St
phone: 5436541232
}]
}

Redux was just going over my head too much. It's so confusing. I think I have to start with smaller exercises to grasp it better.

So I now have three components: Entries.js (which will list each new person), Form.js (simply holds the form) and Parent.js (which holds the state to be changed and the function that runs when the form is submitted)

Parent.js

code:
class Parent extends Component {
    constructor(props, context) {
        super(props, context);
        //set state to an empty array
        this.state = {
            people: []
        };
    }
    handleSubmit = e => {
        e.preventDefault(); //prevent form from refreshing the page
        var myForm = document.getElementById('addform');
        let data = new FormData(myForm); //grabs all the input data from the form
        var eachPerson = {}; //eachPerson will concatonate with this.state, so it will end up being an array of objects
        for (let [key,
            val]of data.entries()) {
            eachPerson[key] = val;
        } //object will end up looking like this {fname: "Joe"}
        var people = [
            ...this.state.people,
            eachPerson
        ] //add the new object to the people array
        this.setState({people});
        document
            .getElementById("addform")
            .reset(); //reset the input fields onsubmit
    }
    render() {
        return (
            <div>
                //form will run handleSubmit when submitted
                <Form onClick={this.handleSubmit}/>
                //the state of parent is passed to entries as a prop
                <Entries people={this.state.people}/>
            </div>
        )
    }
}
Form.js

code:
class Form extends Component {
    render() {
        return (
            <form id="addform" name="addform" onSubmit={this.props.onClick}>
                <input type="text" name="fname" placeholder="First name" required />
                <input type="text" name="lname" placeholder="Last name" required />
                <input type="email" name="email" placeholder="email" required />
                <input type="input" name="address" placeholder="address" required />
                <input type="tel" name="phone" placeholder="phone number" required />
                <input type="submit" id="submitbtn" value="Submit"/>
                <button type="button" id="closebtn" onClick={this.props.onClick}>
                    Close</button>
            </form>
        );
    }
}
Entries.js

code:
class Entries extends Component {
  render() {
    // Parent'js state (an array named people) was passed to entries as a prop //
    // map over each object in the people array
    let peopleData = this
      .props
      .people
      .map((object, index) => {
        // return each property in each object
        return (
          <div key={index}>
            <h1>{object.fname} {object.lname}</h1>
            <p>{object.address}</p>
            <p>{object.email}</p>
            <p>{object.phone}</p>
          </div>
        )
      });
    //display the results of peopleData
    return (
      <div>{peopleData}</div>
    )
  }
}

It works! I'm not sure if it's the most streamlined it can be, I also don't work with React daily so I don't know what would be the most streamlined either, but works is a lot better than not working.

The way you're collecting the inputted data from the form is fishy to me, I think a better way would be something about refs or having the form component be passed an object that it can add its own inputted data to itself, but that's a bridge you can cross later.

edit: Actually I think you can make that a bit better pretty easily by having Form have its own action handler for on-submission-of-form, and then have it call an event handler passed to it through props (from Parent.js) with the data it collects itself. I think refs lets you easily get the values of the inputs in Form.js, so you set up refs for the different form inputs in Form.js, collect it in a new submission handler in Form.js, and then call the event handler/function you're passing in through props from Parent.js with the data you collect from the refs.

edit edit: Maybe refs aren't what I'm thinking of, this seems to fit pretty well with the above though: https://facebook.github.io/react/docs/forms.html

piratepilates fucked around with this message at 00:15 on Feb 9, 2017

luchadornado
Oct 7, 2004

A boombox is not a toy!

OK, here's a real brain buster. We upgraded to Babel 6 and were looking at spec mode:

http://www.2ality.com/2017/01/babel-esm-spec-mode.html

Long story short, your dynamic imports don't meet the spec from what I can tell. Unfortunately, this is how we stub out functions while testing other modules that use those functions.

How are you supposed to stub a function from module A when testing module B that also imports from module A, while remaining spec compliant?

edit: Also, has anyone played around with testdouble or other sinon alternatives? Unit testing is too much of a chore in JS compared to other languages from my experience.

luchadornado fucked around with this message at 01:11 on Feb 9, 2017

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Grump posted:

I ended up doing similar in React, without the actual need for Redux. I don't know what this may look like to you guys, but it seems to work. This will effectively make my form data into an object, put that object into an array (which is the state of the app), and print it out as an entry. I may be making my life harder when I go to edit and delete these entries, but I guess we'll see.

When a new contact gets added, the state ends up looking like this


If it works, then it's Good, so please feel free to ignore this post!

There are a few things you can do to make that "cleaner" that will be helpful to you as you make more complex things.

Functional Components

This:

JavaScript code:
class Thing extends Component {
    render() {
        return (
            <Button onClick={ this.props.onClick }>
               { this.props.label }
            </Button>
        );
    }
}
can be written much more simply as:

JavaScript code:
const Thing = ({ onClick, label }) => <Button onClick={ onClick }>{ label }</Button>
If you only have a render function, you can just use that function as the component. It will be passed in props as an argument. You can still do fancy stuff like mapping and using refs even:

JavaScript code:
const ListThing = ({ things, submitHandler }) => {
     let form;
     const _s = () => submitHandler( form );  // pass this form to the handler!
     return (
          <form ref={( element ) => form = element} onSubmit={ _s }>
              { things.map((thing, idx) => <Thing key={ idx } thing={ thing } /> }
              <button type="submit">LOL!</button>
          </form>
     );
}
Don't tie to the DOM

While getElementById is cool in this case, it means your components aren't reusable unless you can guarantee a single instance of it *ever*. If you do need to refer to a DOM element, use refs where possible.

State management

Again, what you have works, but eventually you'll want to keep your app state outside of components... if you decide to use Parent elsewhere, or it becomes a child component in a larger app, you are in for a world of hurt.

lunar detritus
May 6, 2009


I'm curious about state management. If you're using something like Vuex or Redux, what should go there?

For example I have an accordion component inside a sidebar that can also be collapsed. I think that the accordion's state should manage its own state since I don't really care if the items inside are open or not BUT the sidebar's state (if it's open or not) should be in the store because it's much more probable I'll use that information somewhere else. Is this more or less correct or am I missing something?

lunar detritus fucked around with this message at 17:52 on Feb 9, 2017

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

gmq posted:

I'm curious about state management. If you're using something like Vuex or Redux, what should go there?

For example I have an accordion component inside a sidebar that can also be collapsed. I think that the accordion's state should manage its own state since I don't really care if the items inside are open or not BUT the sidebar's state (if it's open or not) should be in the store because it's much more probable I'll use that information somewhere else. Is this more or less correct or am I missing something?

If no other part of the app "cares" about if the Accordion is open or not, and the Accordion doesn't need to open / close based on any other part of the app (like if you expand List A, the Accordion should close) then that should live in component state. Ditto for the sidebar: if doing something elsewhere in the app will cause it to open / close, then that should live in the UI part of your App state / store . The *only* thing that doesn't go in the store (for me at least) is component level UI that I know will never, ever be needed outside of that component (like your Accordion example.)

Also, no matter how many times I type the word Accordion, I always spell it 'Accordian' the first time. :eng101:

Ochowie
Nov 9, 2007

Lumpy posted:

If you only have a render function, you can just use that function as the component. It will be passed in props as an argument. You can still do fancy stuff like mapping and using refs even:


You can't use refs in functional components.

edit: Looks like you can use refs inside functional components but not on functional components. Sorry about that.

Ochowie fucked around with this message at 19:31 on Feb 9, 2017

ROFLburger
Jan 12, 2006

gmq posted:

I'm curious about state management. If you're using something like Vuex or Redux, what should go there?

For example I have an accordion component inside a sidebar that can also be collapsed. I think that the accordion's state should manage its own state since I don't really care if the items inside are open or not BUT the sidebar's state (if it's open or not) should be in the store because it's much more probable I'll use that information somewhere else. Is this more or less correct or am I missing something?

If you care about the state of a page being retained after a route transition like the user hitting the back button on your single page apps, a store is necessary

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I
I'm writing a React/Redux app that uses a firebase back-end.

I have a CompanyView component that fires off an action with componentWillMount to grab the latest companies node inside firebase, which it then formats the response into an array full of individual company objects and pushes it to my redux store. This all works great, I'm able to render a company list with all the data.

I also have an CompanyAdd view that has a form that lets me input company name and company description. I wrote a bit of logic that runs with onChange to take the value of the company name input field, and reference it against all the company names inside my store state. If the input value matches an already existing company, it'll let the user know that company already exists. This also works fine, but the problem is, a visitor would need to visit the route that mounts CompanyView before going to CompanyAdd, otherwise that initial action inside CompanyView would have never fired off, and the store wouldn't have an array of companies.

My question is, what would be the "proper" way to handle that initial action that grabs the companies data? My initial thoughts were:

1. Have that action fire off on both components using componentWillMount, but that would mean that data is being requested twice if the visitor goes to both components, not so good.
2. Have that action fire off in the root <App /> component that wraps everything inside the app, which would ensure the array of companies is created. My app will have other views that don't care about the list of companies on the store, so this seems like a waste as well.
3. Wrap any views that deal with the company data in a container app, and have that container app fire off the action, so no matter what, any view inside that container will have access to the company list on the store.

I'm leaning towards #3, as it seems like the cleanest option. If this was the case, would it make sense to pass the companies data on the store into the containers children as a prop, or have each child view connect to the redux store using connect()?

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Here's an interesting article from Addy Osmani from Google about the startup penalty of js parsing and compiling on Chrome.

Not a ton of actionable things for front-end devlopers beyond:

  • Ship less JS
  • Do code splitting and lazy-load on your routes
  • Check your frameworks and libraries for their parse cost. As parse/compile is non-linear with the size of js, you can't just compare the shipped byte size of libraries, you have to benchmark their parse/compile time.

He also gives some direction on how to use Chrome devtools to do the actual benchmarking.

Pretty interesting throughout. Kinda cringe-inducing to see this:



and this:

Kekekela
Oct 28, 2004

Ochowie posted:

You can't use refs in functional components.

edit: Looks like you can use refs inside functional components but not on functional components. Sorry about that.

I didn't think you could use them inside either, or at least my linter doesn't like it.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Kekekela posted:

I didn't think you could use them inside either, or at least my linter doesn't like it.

You can't use class property refs but you can set / use the property ref in the manner I showed above to be able to get at th dom node.

EDIT: I guess I phrased it badly in my other post.. I should have said "get and pass a ref of the component" instead of "use refs". Sorry for any confusion.

Lumpy fucked around with this message at 01:28 on Feb 10, 2017

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I

ddiddles posted:

I'm writing a React/Redux app that uses a firebase back-end.

I have a CompanyView component that fires off an action with componentWillMount to grab the latest companies node inside firebase, which it then formats the response into an array full of individual company objects and pushes it to my redux store. This all works great, I'm able to render a company list with all the data.

I also have an CompanyAdd view that has a form that lets me input company name and company description. I wrote a bit of logic that runs with onChange to take the value of the company name input field, and reference it against all the company names inside my store state. If the input value matches an already existing company, it'll let the user know that company already exists. This also works fine, but the problem is, a visitor would need to visit the route that mounts CompanyView before going to CompanyAdd, otherwise that initial action inside CompanyView would have never fired off, and the store wouldn't have an array of companies.

My question is, what would be the "proper" way to handle that initial action that grabs the companies data? My initial thoughts were:

1. Have that action fire off on both components using componentWillMount, but that would mean that data is being requested twice if the visitor goes to both components, not so good.
2. Have that action fire off in the root <App /> component that wraps everything inside the app, which would ensure the array of companies is created. My app will have other views that don't care about the list of companies on the store, so this seems like a waste as well.
3. Wrap any views that deal with the company data in a container app, and have that container app fire off the action, so no matter what, any view inside that container will have access to the company list on the store.

I'm leaning towards #3, as it seems like the cleanest option. If this was the case, would it make sense to pass the companies data on the store into the containers children as a prop, or have each child view connect to the redux store using connect()?


So I did a bunch of googling around about this issue, and a lot of people said it was a good pattern to group your routes with a container component. I went ahead and did that, but it kind of doesn't feel like a good solution. This is what I came up with so far.

Router
code:
<Router history={browserHistory}>
      <Route path="/" component={App}>
        <IndexRoute component={FrontPage} />
        <Route path="company" component={Company}>
          <IndexRoute component={CompanyView} />
          <Route path="add" component={CompanyAdd} />
        </Route>
      </Route>
</Router>
Company container component, will render either CompanyView or CompanyAdd component depending on the route. Passes down the companyList store state using React.cloneElement
code:
class Company extends Component {
  componentWillMount() {
    this.props.getCompanies();
  }
  render() {
    const propsToPass = { 
      ...this.props.companyList,
      addCompany: this.props.addCompany,
      getCompanies: this.props.getCompanies
    }
    const childrenWithProps = React.cloneElement(this.props.children, propsToPass);
    return (
      <div>
        { childrenWithProps }
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    companyList: state.companyList
  }
}

export default connect(mapStateToProps, { addCompany, getCompanies })(Company);
CompanyView, no longer connects to the redux store
code:
const CompanyView = ({ companies }) => {
  const RenderCompanyListItem = (props) => {
    return (
      <div className="col-xs-12 col-md-6">
        <div className="row">
          <div className="col-xs-12 col-md-3">
            <img src={companyImageTemplate}/>
          </div>
          <div className="col-xs-12 col-md-9">
            <span>{props.companyName}</span>
            <span>{props.companyDescription}</span>
          </div>
        </div>
      </div>
    );
  }

  const renderCompanyList = companies.map((company) => {
    return (
      <RenderCompanyListItem
        key={company.id}
        companyName={company.companyName}
        companyDescription={company.companyDescription}
      />
    );
  });

  return (
    <div>
      { renderCompanyList }
    </div>
  );
}

export default CompanyView;
I could add some logic to the Company.js container component to only pass in specific parts of the companyList store state to its child depending on what component is it's child.

Is this a good pattern? Or am I totally off?

luchadornado
Oct 7, 2004

A boombox is not a toy!

Thermopyle posted:

Here's an interesting article from Addy Osmani from Google about the startup penalty of js parsing and compiling on Chrome.

Not a ton of actionable things for front-end devlopers beyond:

  • Ship less JS
  • Do code splitting and lazy-load on your routes
  • Check your frameworks and libraries for their parse cost. As parse/compile is non-linear with the size of js, you can't just compare the shipped byte size of libraries, you have to benchmark their parse/compile time.

He also gives some direction on how to use Chrome devtools to do the actual benchmarking.

Pretty interesting throughout. Kinda cringe-inducing to see this:



and this:



Even when I show people flamecharts depicting 1 second parse times for React and the initial model for a Top 1000 traffic website, they don't think it's that big of a deal. Nothing is free, damnit - all those libraries and whatnot have a cost. They'll then argue in a code review about how you should use lodash's find() function instead of the baked in filter() because lodash is so much faster (it's actually slower in that specific case), and the difference still comes out to be something like .000001 seconds for the use case in question. loving maddening.

Plavski
Feb 1, 2006

I could be a revolutionary

Helicity posted:

Even when I show people flamecharts depicting 1 second parse times for React and the initial model for a Top 1000 traffic website, they don't think it's that big of a deal. Nothing is free, damnit - all those libraries and whatnot have a cost. They'll then argue in a code review about how you should use lodash's find() function instead of the baked in filter() because lodash is so much faster (it's actually slower in that specific case), and the difference still comes out to be something like .000001 seconds for the use case in question. loving maddening.

My tech lead gets pissed when I bring him examples of complex js optimizations we could make where the difference is 0.01s over 10,000 iterations. "I'd rather have readable code that's slower than unreadable nonsense no-one else will be able to read after we fire you for writing unreadable code."

Doesn't stop me tho :)

Munkeymon
Aug 14, 2003

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



Plavski posted:

My tech lead gets pissed when I bring him examples of complex js optimizations we could make where the difference is 0.01s over 10,000 iterations. "I'd rather have readable code that's slower than unreadable nonsense no-one else will be able to read after we fire you for writing unreadable code."

Doesn't stop me tho :)

But that really wouldn't help if you're not running that code 10k times in a page lifetime :confused:

Munkeymon
Aug 14, 2003

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



Helicity posted:

OK, here's a real brain buster. We upgraded to Babel 6 and were looking at spec mode:

http://www.2ality.com/2017/01/babel-esm-spec-mode.html

Long story short, your dynamic imports don't meet the spec from what I can tell. Unfortunately, this is how we stub out functions while testing other modules that use those functions.

How are you supposed to stub a function from module A when testing module B that also imports from module A, while remaining spec compliant?

edit: Also, has anyone played around with testdouble or other sinon alternatives? Unit testing is too much of a chore in JS compared to other languages from my experience.

This is what you're talking about, right?

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

ddiddles posted:

So I did a bunch of googling around about this issue, and a lot of people said it was a good pattern to group your routes with a container component. I went ahead and did that, but it kind of doesn't feel like a good solution. This is what I came up with so far.

:words:


What I did in my Firebase / React app is throw listeners onto the Firebase paths for all the collections I'd need in the app at launch. When they initialize or whenever there is an update, the store is updated via action. Only happens once, app has all the base data it needs no matter what, and I don't have to do anything else. Is it "wasteful" if I never go to the part of the app that needs X part of the state? Maybe, but the app is performant, so I don't worry about it. Don't prematurely optimize! If loading that data brings the app to a crawl on launch, sure, worry, but do what's easy then profile if things get slow.

Plavski
Feb 1, 2006

I could be a revolutionary

Munkeymon posted:

But that really wouldn't help if you're not running that code 10k times in a page lifetime :confused:

Of course it wouldn't, and those ones are usually just to gently caress with him. However, we work with .NET and SharePoint a lot, and you can get a good amount of boost by really crushing a lot of iteration logic deep down. We re-factored a method the other day to be more confusing to an outsider, but gave us a 10 times better performance boost. Easy to make that call, but harder to make a 5% boost case. They all add up though; a few pieces of tough code here and there can end up with an overall boost that's noticeable. But it's a balancing act that doesn't always come out in the favour of the end user, and sometimes maintenance just takes preference.

Forgall
Oct 16, 2012

by Azathoth
Is compilation output cached by browsers?

Munkeymon
Aug 14, 2003

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



Forgall posted:

Is compilation output cached by browsers?

They mention in the article that V8/Chrome will cache a script after the third run in 72 hours.

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I

Lumpy posted:

What I did in my Firebase / React app is throw listeners onto the Firebase paths for all the collections I'd need in the app at launch. When they initialize or whenever there is an update, the store is updated via action. Only happens once, app has all the base data it needs no matter what, and I don't have to do anything else. Is it "wasteful" if I never go to the part of the app that needs X part of the state? Maybe, but the app is performant, so I don't worry about it. Don't prematurely optimize! If loading that data brings the app to a crawl on launch, sure, worry, but do what's easy then profile if things get slow.

Thanks man.

I have the bad habit of wanting the first code I write to be the final code I write, so I just sit there wringing my hands thinking "I'm probably doing this wrong", and it stops me from actually getting anything done.

We seem to think alike, because I forced myself to have the Company container call an action that sets up a listener that grabs the company data on load and any time it updates, and then turning off that listener every time the Company container un mounts.

Adbot
ADBOT LOVES YOU

Kekekela
Oct 28, 2004

Munkeymon posted:

But that really wouldn't help if you're not running that code 10k times in a page lifetime :confused:

Sometimes you just gotta scratch that itch.

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