ebenStickney / KanBan

React Kanban Work
0 stars 0 forks source link

Misc questsions #1

Open lefnire opened 6 years ago

lefnire commented 6 years ago

One more concept I am having trouble explicitly defining:

export default, with the props in curly brackets. I understand that this book is primarily using function based component, with a couple of exceptions (code cademy spent most of the time using class based components). But from what I've read on code cademy, and on the react site, when you want to pass a prop to a function based component, or rather when that component calls the prop, prop is usually put in as the argument. For example:

are these components different? Also, are they anonymous or something?


I made you a collaborator on this stuff. so, Two questions to start the day.

  1. I think I am starting to understand the rules of export default a bit better, but any clarification you can provide is great, in particular: Can you explain what is happening in Notes.jsx? I have export default in front of a couple props, and some functions, all passed as arguments, but it's a bit messy for me.
  2. I'd love to learn more about bind. I've really only seen it in relationship with this. and that I think has to do with scope. But here it is being used with (null, id) in Notes, with all of the functions. So how should I understand this? rephrase: I've only seen it with in relationship to this.function = this.function.bind(this). so how should I understand t̶h̶i̶s̶ bind.

  1. In note, I removed the control over what is rendered inside of it up to Notes, and replaced it with new props, children and ...props.

conceptually I think I understand what is happening, but I've just never heard of or seen children, and I've never used ... props I think I can continue and keep up, but I don't know how these props allow for the rendering to be passed up to Notes.

lefnire commented 6 years ago

So yesterday first. Firstly, regarding export default. export itself doesn't have anything to do with the function structure - what the line is saying is "define a function bla bla, then export it." (you could replace export default with let myFn =). export says "make these bits from this file available to other files, in case they need them (via import {a, b} from __). export default says "this is the only thing I'm exporting from this file - so when they import from me, the import just this bit (via import a from __).


So the function part. React allows for components to either be class A extends React.Component{} or function A(){} (as you know). It has some internal joojoo for determining which you used, and handling accordingly. I personally like to use the class approach, but the world seems to be moving towards the function approach (something called "functional programming", "immutability", and stuff you'll see along the way). It's a principles thing. Eh.

Anyway, when you define a function, here are some options:

let fn = (a, b) => a + b;
let fn = (a, b) => {return a+b};
function(a, b) {return a+b;}

All the same thing. You'll see the "anonymous function" approach used a lot in react to save on code, like <div onClick={()=>alert("HI")}>Click Me</a>. Now, let's say the function takes only one argument: let fn = (obj) => obj.a + obj.b. That function uses a and b from obj & returns the sum. Well, using argument destructing we've discussed before, you can say the same thing like this: let fun = ({a, b}) => a + b. That says "take one argument, which we won't even name, because we're gonna just strip two things out of it: a and b (those exact attributes must exist on the original object). So these are the same:

let fn = (obj) => obj.a + obj.b;
let obj = {a: 1, b: 2};
fn(obj); // => 3

let fn = ({a, b}) => a + b;
let obj = {a: 1, b: 2};
fn(obj); // => 3, same.

Slick! So why do we care / why do #2? Because if we used #1, React wouldn't know what arguments, in what order, how many to pass to our functional component. If we had MyComponent = (a, b, c) => (<div onClick={a}>{b}! {c}?</div>) how would React know that we expect 3 arguments? So it takes the easy route and says "I'm gonna pass you a plain object, you take what you need out of it." You could use either (obj) => obj.a, .. or ({a}) => a, ...`.

lefnire commented 6 years ago

I think I am starting to understand the rules of export default a bit better, but any clarification you can provide is great, in particular: Can you explain what is happening in Notes.jsx? I have export default in front of a couple props, and some functions, all passed as arguments, but it's a bit messy for me.

Does the above answer your question, or do you have more?

I'd love to learn more about bind. I've really only seen it in relationship with this. and that I think has to do with scope. But here it is being used with (null, id) in Notes, with all of the functions. So how should I understand this? rephrase: I've only seen it with in relationship to this.function = this.function.bind(this). so how should I understand t̶h̶i̶s̶ bind.

Bind says: "take this function. any time the function sees the word this inside, replace it with what I'm giving you now". myFn.bind(frank) says "myFn, which used to have its own this inside it (whatever that may be) - I want it to always use frank instead.

It's a pretty complex concept actually, but it's good you ask because it might be brought up in interviews. A common case in React is the that class A extends React.Component(){} - methods inside that class often don't get the correct this (they don't refer to the class they're in) due to some wonky JavaScript history. It's especially the case when your'e deeply nested inside functions (functions inside functions) - this usually refers to the function it's a part of, but you usually prefer it to refer to whatever's at the top (the class itself). So you can bind them explicitly. There are many ways to skin a cat. Two alternatives:

class A extends React.Component {
  sum = ({a, b}) => a + b; // This = _ => thing says "make a method, then bind it to me

  // that's the same as:
  constructor() {
    this.sum = this.sum.bind(this);
  }
  sum({a, b}) {return a + b;}
  // 1's much cleaner, no?

  // now here's the issue we're trying to solve in the first place.
  doSomething(val) {alert(val);}
  sum({a, b}) {
    return this.doSomething(a + b);
    // `this` here does _not_ refer to the class `A`, but instead to the function `sum`. `sum.doSomething` doesn't exist, so you'll get an error. So we explicitly bind in these cases; it's like a bandaid, "look dummy - you're a method in a class, he's your master - shove `this` down your gullet and don't be stupid."
  } 
}
lefnire commented 6 years ago

In note, I removed the control over what is rendered inside of it up to Notes, and replaced it with new props, children and ...props. conceptually I think I understand what is happening, but I've just never heard of or seen children, and I've never used ... props I think I can continue and keep up, but I don't know how these props allow for the rendering to be passed up to Notes.

Actually a lot of these questions are ES6 things. ...props, fn({a, b}), export default, etc - all ES6 - so you may want to get your hands on an ES6 primer or Udemy course or something. It's actually really quick (there's only a handful of those "shortcuts"), so it shouldn't bog you down.

Ok, ...props does this. It's kinda funky. Let's get back to "object destructuring" it's called. You've seen it in multiple ways:

let obj = {a: 1, b: 2};

const {a, b} = obj; 
// same as: `const a = obj.a, const b = obj.b`

let myFn = ({a, b}) => a + b;
// same as: `let myFn = (obj) => obj.a + obj.b

import {a, b} from 'some-package';
// same as `import a from 'some-package.a'; ??? actually, I'm not sure.. but you get the idea

In these cases we strip a & b from object. They're named the same in the new place (function, or consts, etc) as the old place (obj). Now, you may not have taken all the attributes off. Maybe obj has c too - obj = {a:1, b:2, c:3}. What you can do is say "I want these specific attributes: a & b. Then I want the rest of the attributes in a bucket over there." That's what ...props says; it's called a "rest" operator ("the rest of __"), and it puts everything that you didn't explicitly strip off obj via destructuring, into another object called props.

lefnire commented 6 years ago

I think I've answered everything. If you have more, or I left anything - ask away.

lefnire commented 6 years ago

oh, props.children.

children is a special attribute that gets tacked onto props automatically by React (you don't pass it yourself). It has in it the nested components inside your component.

So, let's say you have:

class HeaderLink extends React.Component {
  render() {
    const {props} = this; // same as `const props = this.props`, just for less typing below
    return <a href={props.link}>{props.text}</a>
  }
}
class Header extends React.Component {
  render() {
    return (
      <div className="header">
        {/* A bunch of pretty header html/css */}

        {/* This will render the links which were nested inside this component in App below */}
        {this.props.children}
      </div>
    ) 
  } 
}

class App extends React.Component {
  render() {
    return (
      <Header>
        {/* Note how we put <HeaderLinks /> _inside_ <Header/>. That's what props.children is for, Header will determine where those inside-components should go */}
        <HeaderLink link="google.com" text="Google" />
        <HeaderLink link="apple.com" text="Apple" />
      </Header>
    );
  }
}
ebenStickney commented 6 years ago

I still don't understand children. You said it's not something that gets passed. so what is happening here: image in relation to its parent here:

image

is it the same as your example?

lefnire commented 6 years ago

It's the same as mine, yeah. children isn't something you pass as a variable explicitly. It's something React passes in for you, based on the structure of your HTML. So in your example, <Note> has inside of it the span & button. Those collectively are children. Then inside the <Note> function, you pull it out of props by name (object destructering), and you say exactly where those two are supposed to go (the place where {children} is in the html).

So: You have a component, it takes props, you specify those props (<Note a={1} b={2} />). ALSO, if that component has other stuff nested inside (the span & button there), those also get tacked on as props.children. So it's like React modifies your code to look like <Note a={1} b={2} children={span & button} />.

So now, in the <Note> function, children is just like anything else in your props object, and you can slot it into the HTML wherever you want.

ebenStickney commented 6 years ago

You may be saying exactly this, or I may be understanding it incorrectly:

before, I had the crossed out bit in note:

image

the span and button, written in html-like jsx. with the two props, task and onDelete being passed in. ANd in Notes I had the self-closing tag of Note, with the props included.

But now I have what you just described. The children in Note, representing everything in Notes that is written between Note in Notes.

I guess my last last question on this is about how ...props is being used. In this instance, does ...props equal task and onDelete? If so, why are they being included inside of the opening div tag?

lefnire commented 6 years ago

The above side-by-side are pretty different, actually; they're not quite equivalents. Here's what they're saying:

1st) This component expects props passed with task and onDelete. Then I'll put those two things into place exactly as so.

2nd) Honestly, this component is pretty useless. What it's saying is: give me some junk, it can be whatever you want (...props) and I'll throw it on a div as attributes (so this could be className, style, onClick, etc). Also, have nested inside yourself some more html, and I'll put them inside the div. In this way, ...props is not task + onDelete; those are expected to be contained within children. Instead, ...props is a blank-slate for the caller to throw any extra attributes on the containing div they want.

Here's why the second one is useless. Let's call them A & B.

<B onClick={()=>alert('hi')}>
  <span>...</span>
</B>

// Is the same as

<div onClick{()=>alert('hi')}>
  <span>...</span>
</div>

// Which is the exact same amount of code as not having the component in the first place. 
// Ie, that second component does exactly nothing; using a div directly is the exact same thing.
// the onClick gets pass into ...props, and the <span> is the children