How do you make a Media component in React? ```jsx var Media = React.createClass({ }); ``` We then need to export our component so it can be used outside this file. ```js module.exports = { Media: Media }; ``` Every component needs a render function This tells the browser what HTML to render. // just rendering a paragraph for now // `this.props.children` tells react where to put any child nodes. ```jsx var Media = React.createClass({ render: function () { return (

{this.props.children}

); } }); ``` Let's try it. Sweet, this is gonna be rad! ```html My very first React component! ``` When React renders that component we get this html ```html

My very first React component!

``` Not very useful, right? Well, you'd never use react to render a simple paragraph because it already understands `

` tags, you can just use them! What if we want to start building an actual media block? Let's add a left image. # What did we try first? # Tons of attributes ```html Media block content ``` How does it work? Well, remember the render function in our component? It snags the leftImageSource attribute and sets it as our image source. (for now we'll focus on api stuff) So, we thought we were pretty clever, then we realized sometimes the image was a link, so we added an `href`. ```html Media block content ``` ```html Media block content ``` Oh, and we need to handle the images vertical alignment ```html Media block content ``` Oh shoot, accessibility, we need an alt atribute. ```html Media block content ``` Oh, and performance! We need a height and width! ```html Media block content ``` The space between the image and the content can vary, so we'll need `leftImageSpacing`. ```html Media block content ``` Oh, and we'd better add all the properties for the media block itself Including stacksize (breakpoint) and bodyAlignment (vertical alignment of body content) ```html Media block content ``` This is getting out of hand! But we forgot something, the media block can also have a right image, so we'll need to duplicate all that. ```html Media block content ``` This is out of control, we are going the **wrong way**! What is working here? * It's very explicit, we know what each thing does What isn't? * We're basically recreating html in React, yuck! (we shouldn't make a new different alt attribute!) * We have image properties and media properties all mixed up * So what did we think of next? # JSON ```js var images = [ { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" }, { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" } ]; ``` Which we can put into our Media component like so: ```html Media block content ``` We never actually built this, because we weren't satisfied with it, but let's talk about what works and doesn't What works? * cleaner separation of concerns (media takes care of media stuff, rather than the properties of it's children) What doesn't work? * It isn't that different than what we had before * The abstraction of passing in JSON means all the code isn't in the same place * It's a little weird to have JSON in the middle of what looks like markup (IMO) * We're really still reinventing html atributes that react would give us for free on an `` element. So, what did we try next? # Parsing Children We decided to try including the images as children. ```html profile photo

My media content

profile photo ``` This looked better, everything is normal html! But, it has a few drawbacks. What works? * Normal HTML * Facebook does it this way What doesn't work? * The images and body content need to be in a very particular order, it seems weird to expose that to the user * Violates the *"build components you can use without understanding CSS"* * We could loop over children and reorder them, but how do we tell the difference between content images and media images? * We were still discovering React, and didn't know *how* to loop over children yet * React provides handy error messages and property validations. We would lose out on that if we made the images children * Facebook's images aren't optional, so it's a different case So what did we try next? # React built in `` Component In react, people joke that everything is a component. It's not a joke, everything is. First, we make our image. ```jsx var leftImage = profile photo; var rightImage = profile photo ``` Next, we make our media object. ```html Media block content ``` You'll notice this looks similar to the JSON example. You can even write it like this if your really want to. ```html } bodyAlignment='middle' stackSize='medium'> Media block content ``` What works? * React passess default html attributes in to the resulting img tag, so we don't have to do anything special with height, width, src, and alt. * Aria values would also be passed through * We separate concerns and the image takes care of it's own properties * No need to parse the content What doesn't work? * HTML inside an attribute (in the latter example) is a bit odd, though it does have advantages. * Remember how I said default HTML attributes are passed through? The href will also be passed through. So our image will have an href attribute. I like clean html, and that feels weird to me! ```html
... ``` We considered going back to properties. ```html ``` But ultimately decided we should make our own `` wrapper so we'd have more control. We thought this would probably crop up again. So, what did we try next? # Custom Image component Our component was born. It outputs a simple `` tag, but won't pass through attributes that don't make sense like `href`. We'll need to create an image component, just like we did the Media component. ```jsx var Image = React.createClass({ }); ``` And export it the same way we did the Media component ```js module.exports = {Image}; ``` And let's make it get it's properties and render an image ```js var Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; var image = {children}; return href ? {image} : image; } }); ``` Now, our images can be responsive, meaning they fit their container, whatever size it flexes to be, so let's handle that property. ```jsx var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; var image = {children}; return href ? {image} : image; } }); ``` And we'll need to apply the `img-responsive` class if we find that property has been set to true. ```jsx var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); var image = {children}; return href ? {image} : image; } }); ``` Finally, one of the advantages we talked about for using properties over children is the validation and error handling we can do as a result. ```jsx var Image = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); var image = {children}; return href ? {image} : image; } }); ``` Here we're saying * responsive has to be true or false * href is a string * src is a string and is required @@@ show example of an error message if src is missing @@@ This is really powerful, because now, developers who use this component won't have to wonder why it isn't working, we can give them nice error messages on the console in their browser of choice. At this point, it was really starting to work well for us, but this is when we had the "ah-ha" moment. Users are still needing to specify too many things to get this component to work, they might as well just write html! So, what did we do next? # Elements We could simplify our interface further! Our designers only ever used two kinds of alignment: 1. Traditional media with everything top aligned @@@ photos of these components @@@ 2. "Flag" component a la Harry Roberts So we thought, let's make those two use cases dead simple. 1. We changed our default media componetn to default to top alignment if nothing else was specified. 2. We created a `Flag` component ```html Flag content (often just a link) ``` What works? * With Flag and Media, we no longer need to specify alignment unless we want something weird. What doesn't work? * Engineers don't always know what the flag object is. Documentation and designer's teaching helps. # Conclusion Are any of these wrong? No, absolutely not. Facebook uses the child nodes method. We use the final version. Both work well. For our charts and panels, we loop over children. Our buttons use more elements and have almost no props. For tables, we use JSON to give them maximum configurability. Each component is different. It's a design decision. Other devs, who will build more complex views out of your simple components are your users. You have to user test. (What seems logical to you when you are neck deep in it all will not be logical to anyone else.) Keep looping back. Change the interface until it works well. Use all the tools in your toolbox: 1. Elements 2. Simple attributes 3. Built in React elements 4. Custom Elements 5. JSON 6. Children Last week we got feedback from our New York team that our components are a bit too strict. They ended up having to use plain html more than they wanted to because we didn't allow them to pass through class names the way the wanted to. So now we have something else to make better! We started thinking, and [collaborating with some smart folks on a gist](https://gist.github.com/stubbornella/e97662e4a197eb9a534a). And decided to try passing in an `` instead of JSON.