Type of Components - askbid-notes/notes-react GitHub Wiki
- Functional Component
- Container and Presentation Components
- Functional Component as a Stateless Function
- Separating Concerns Using a Container Component
- Fragments
- Exercise 4 - Functional Component
The main take away here is the difference between class and functional components. Class components are versatile and fully featured components. They can be anything we want them to be. Functional components exchange the class component's bells and whistles for simplicity and a small performance boost.
import React, { Component } from 'react'
class App extends Component {
render() {
return <div></div>
}
}
export default AppDoes an automatic comparison of old and new props and state therefore not having shouldComponentUpdate.
import React, { PureComponent } from 'react'
class App extends PureComponent {
render() {
return <div></div>
}
}
export default AppAlthough React is clever when it comes to rendering class components, every class component, when rendered, goes through a series of checks related to its lifecycle. If we do not need to use state or lifecycle methods, we can avoid these checks by writing a functional component.
import React, { PureComponent } from 'react'
class App extends PureComponent {
render() {
return <div></div>
}
}
export default App
// simpler form:
import React from 'react'
const App = props => <div>{props.greeting}</div>
export default Appfor instance we can use it for a reusable Button component that has a consistent style but receives props that define its text and click event
import React from 'react'
const Button = ({ handleClick, text })=> <button style="myButton" onClick={ handleClick }>{ text }</button>
export default Buttonnotice the technique to use {key} consist in the objects passed into the function is deconstructed as this
{key1} = {key1: 1, key2: 2} //=> 1
These are not different types of components, but instead, are a way of thinking on how to organize a React app.
Presentational components are only concerned with displaying content. They typically don't deal with state, or have a lot of added logic within them. They receive props and display content. The Button component from the functional component section above is a great example of this.
In React, we can compartmentalise - each piece can be a component (NavLinks, Menu, Search, etc..) and since they all go together, we can create a parent component, that acts as a container for everything:
import React, { Component } from 'react'
import Logo from './Logo'
import NavLinks from './NavLinks'
import DropMenu from './DropMenu'
import Search from './Search'
class NavigationContainer extends Component {
state = {
query: "",
username: ""
}
render() {
// <>...</> is a a React fragment - it does not render anything to the DOM, but can wrap multiple JSX elements
return (
<>
<Logo />
<NavLinks />
<DropMenu username={ this.state.username }/>
<Search query= {this.state.query } handleChange={ this.handleChange } handleSubmit={ this.handleSubmit }/>
</>
)
}
handleSubmit = event => { ... }
handleChange = event => { ... }
}Using this sort of set up, none of the imported components need to have their own state, nor do they need to have any functions defined. Container components, like NavigationContainer, deal with managing state and class methods.
Keeping all the more complex logic in one place makes it easier to follow the flow of information. It also keeps many components simpler and free of clutter.
Container components, having to deal with state, are usually class components. Presentational components are most often functional components as they don't need to contain custom methods, relying mainly on props.
Imagine that we've composed the majority of a UI out of these simple presentational components -- all of them almost entirely stateless, all of them designed to do one thing and one thing well: they just receive props from their parent components and render! That's it. They are simple and beautiful and because they aren't doing much, because they are mostly stateless, they have a better chance of remaining blissfully bug free! This is the power and importance of presentational components. They are simple and they just work. So therefore we should strive to use them as much as possible.
A component that has no state means that our component doesn't even really need to be a JavaScript object of type Component at all. It can just be a simple function — one that takes an input and returns a (portion of) the UI.
const defaultLimit = 100
const TextField = (props) =>
<input
className="field field-light"
onChange={props.onChange}
limit={props.limit || defaultLimit}
/>;With this our application is more predictable -- and here we can see the influence of the principles of functional programming on React -- that this function will always return the same UI output if given the same props. There are no state variables here that could be set to different values at different times that might lead the function to return something that we didn't predict. What we have here, then, is what in functional terms is called a "pure" or "referentially transparent" function. see what makes a function a true pure function
class BookList extends Component {
constructor(props) {
super(props);
this.state = {
books: []
};
}
componentDidMount() {
fetch('https://learn-co-curriculum.github.io/books-json-example-api/books.json')
.then(response => response.json())
.then(bookData => this.setState({ books: bookData.books }))
}
renderBooks = () => {
return this.state.books.map(book => {
return (
<div className="book">
<img src={ book.img_url } />
<h3>{ book.title }</h3>
</div>
)
})
}
render() {
return (
<div className="book-list">
{ this.renderBooks() }
</div>
)
}
}this component has tightly coupled together a whole set of assumptions about the data layer with another set of assumptions about the presentation layer. This is less than ideal.
breaking up the original component into a few pieces we would obtain the following: All the state is contained in our container component BookListContainer. The logic is the same, but it is has been uncoupled from the presentation layer, which is now contained in the BookList and Book components. Those components, which are stateless, are now incredibly stable as well as concise.
// src/Book.js
import React from 'react';
const Book = ({ title, img_url }) => (
<div className="book">
<img src={ img_url } alt={title}/>
<h3>{ title }</h3>
</div>
)
export default Book;
// src/BookList.js
import React from 'react';
import Book from './Book';
const BookList = ({ books }) => (
<div className="book-list">
{ books.map(book => <Book title={book.title} img_url={book.img_url} />) }
</div>
)
export default BookList;
// src/BookListContainer.js
import React from 'react';
import BookList from './BookList';
class BookListContainer extends React.Component {
constructor() {
super()
this.state = {
books: []
};
}
componentDidMount() {
fetch('https://learn-co-curriculum.github.io/books-json-example-api/books.json')
.then(response => response.json())
.then(bookData => this.setState({ books: bookData.books }))
}
render() {
return <BookList books={this.state.books} />
}
}
export default BookListContainer;class ChildComponent extends Component {
render() {
return (
<div>
<p>Hey, I am a child</p>
<p>My name is child component</p>
</div>
)
}
}
class ParentComponent extends Component {
render() {
return (
<div className="parent">
<ChildComponent />
<ChildComponent />
</div>
)
}results in:
<div class="parent">
<div>
<p>Hey, I am a child</p>
<p>My name is child component</p>
</div>
<div>
<p>Hey, I am a child</p>
<p>My name is child component</p>
</div>
</div>but we can use React.Fragment
class ChildComponent extends Component {
render() {
//The wrapping 'div' here has been replaced with a React fragment
return (
<>
<p>Hey, I am a child</p>
<p>My name is child component</p>
</>
)
}
}
class ParentComponent extends Component {
render() {
return (
<div>
<ChildComponent />
<ChildComponent />
</div>
)
}
}results in:
<div>
<p>Hey, I am a child</p>
<p>My name is child component</p>
<p>Hey, I am a child</p>
<p>My name is child component</p>
</div>