Component Principles

Component Principles

  • Keep it stupid
  • Keep it scoped

Keep it stupid

  • Solve one problem well
  • Functionally pure
  • Self-contained (No side-effects)
  • Handle basic html attributes (className)

Solve one problem well

  • Style is a problem
  • Behavior is a different problem
  • Different components should solve each
  • Composing them can be another problem

Functionally pure

  • Should return the same thing for a given set of props

Self-contained (No side-effects)

  • Don't modify things outside of itself
  • Side-effects are their own problem

Handle basic html attributes

  • If it's just an opinionated html element, it should accept all attributes that element could accept
const Button = ({ children, ...props }) => (
	<StyledButton {...props} >{ children }</StyledButton>
)

Keep it scoped

  • Styles itself, Positions its children
  • Props and hooks only
  • Encapsulate opinion. Then compose.

Styles itself, Positions its children

  • A child's style is its own problem to solve
  • A child's position is a problem for the parent to solve
.component {
  & > .component-part {
    margin: auto;
  }
}

Props and hooks only

  • Should be pure functions
    • Deterministic
    • No Side Effects
  • ​Avoid globals
  • Avoid unconventional methods
    • useRef
    • React.children

Encapsulate opinion. Then compose.

const Contrived = () => {
	const foo = useFoo()
    const bar = usebar()
    
    return (
    	<div>
        	<h1>{foo}</h1>
            <button onClick={bar}>Submit</button>
        </div>
    )
}

Encapsulate opinion. Then compose.

const useContrivedData = () => {
	const foo = useFoo()
    const bar = usebar()
    
    return {
    	foo,
        bar,
    }
}

const _Contrived = ({ foo, bar = () => {} }) => (
  <div>
    <h1>{foo}</h1>
    <button onClick={bar}>Submit</button>
  </div>
)

const Contrived = () => {
	const data = useContrivedData()
    
    return </ {...data} _Contrived>
}

deck

By Matthew Poulson

deck

  • 44