How to do presentational components

What's a presentational component?

Introduced in "Presentational and Container Components", "presentational components" are React components that

  • Are concerned with how things look.
  • May contain both presentational and container components inside, and usually have some DOM markup and styles of their own.
  • Often allow containment via this.props.children.
  • Have no dependencies on the rest of the app, such as Flux actions or stores.
  • Don’t specify how the data is loaded or mutated.
  • Receive data and callbacks exclusively via props.
  • Rarely have their own state (when they do, it’s UI state rather than data).
  • Are written as functional components unless they need state, lifecycle hooks, or performance optimizations.

Examples: Page, Sidebar, Story, UserInfo, List.

Example presentational component

A presentational component is written as a file in ${topic}/components/${name}.

We will use:

Here is an example 'counter' component within the 'count' topic:

// count/components/counter.js

// imports
import React, { Component } from 'react'
import { createComponent } from 'react-fela'
import styles = require('../styles/counter')

// styled components
const Container = createComponent(styles.container)
const Button = createComponent(styles.button, 'button', ['onClick'])
const Input = createComponent(styles.input, props => {
  return <input type='number' />
}, ['value', 'onInput')

// exported component
export default props => {
  const { value, increment, decrement, set } = props

  return <Container>
    <Button
      onClick={handleClick(increment)}
      type='increment'
    >
      +
    </Button>
    <Input
      onInput={handleInput(set)}
    />
    <Button
      onClick={handleClick(decrement)}
      type='decrement'
    >
      -
    </Button>
  </Container>

  function handleClick (action) {
    return ev => action()
  }

  function handleInput (action) {
    return ev => {
      ev.preventDefault()
      action(Number(ev.target.value))
    }
  }
}
// count/styles/counter.js

export default {
  container: props => {
    display: 'flex'
  },
  button: props => {
    backgroundColor: buttonColors[props.type]
  },
  input: props => {
    padding: '1rem'
  }
}

const buttonColors = {
  increment: 'green',
  decrement: 'red'
}

results matching ""

    No results matching ""