Skip to content

Instantly share code, notes, and snippets.

@nahumzs
Last active May 10, 2022 01:01
Show Gist options
  • Save nahumzs/e5429c9b95db73a0540159803c9dd433 to your computer and use it in GitHub Desktop.
Save nahumzs/e5429c9b95db73a0540159803c9dd433 to your computer and use it in GitHub Desktop.
React patterns πŸ˜»πŸ¦„
// Children Extend Pattern
// when to use it:
// `Children Extend` is a pattern which focuses on passing down the state of the parent component to its children
// Solving the problem that arise when a children component want to comunicate with their parent.
// pros:
// Simple to pass down state or a `callback` with basic javascript knowledge
// Easy to understand, is just about extending a javacript object.
// cons:
// Requires a fixed `JSX` structure for the parent to be able to clone its children with their right state:
// this will work:
// <Tabs>
// <Tab></Tab>
// <Tabs>
//
// this will break the implementation:
// <Tabs>
// <div> {/* <-- this will be the clone children, breaking implementation */}
// <Tab></Tab>
// </div>
// <Tabs>
// Example:
import React, {Component} from 'react';
export default class Form extends Component {
canIDoSomething = () => {
return Promise.resolve(true)
}
render() {
// this is a React utility to map over react children and allow to clone and extends
// the Form childrens
const children = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {
isFormDisabled: this.props.isDisabled,
canIDoSomething: this.canIDoSomething
});
});
return (
<form>
{children}
</form>
);
}
}
export const Input = (props) => {
return <input type="text" disabled={props.isFormDisabled} />
}
export const Button = (props) => {
const doSomething = () => {
props.canIDoSomething().then(response => alert(response))
}
return (
<button
disabled={props.isFormDisabled}
onClick={doSomething}
>
go
</button>
)
}
// Hybrid Components
// when to use it:
// When the component needs to manage it's own state (Uncontrolled component)
// and also provide the flexibility to be controlled by the developer (Controlled Component).
// A Hybrid Component.
// pros:
// - Give the flexibility to the developer who can decide if he wanna handle the component state or
// let the component do it.
// - Easily composable since works as Controlled Component
// cons:
// "Double implementation", you should handle the case when the developer pass a prop and behave as Controlled Component and when the developer
// omit it, handle the state automatically,
// TIP: Never try to sync the inner state of the component, this kind be challenge and can lead to a lot of bugs instead use the props to decide if
// you should look into the props or the state
// TIP2: When a component has more than 1 prop, you have to option:
// decide if you want provide controlled and uncontrolled behaviors for each prop or 1 prop defined if the component behaves completerly
// as controlled or uncontrolled.
// Personally even if required more work I prefer to check for each property and decide if should behave as controlled or uncontrolled, which
// gives a better UX to dev consumer.
// example.
import React, { Component } from 'react';
import './ControlledUncontrolled.css';
export default class Collapsible extends Component {
state = {
// this state will be use by the uncontrolled component
startCollapsed: this.props.startCollapsed || true,
}
/***
How to detect if it's controlled or not
***/
isControlled() {
return typeof this.props.isCollapsed !== "undefined"
}
onClick() {
if(this.isControlled()) {
this.props.onClick()
return
}
this.setState({ startCollapsed: !this.state.startCollapsed })
}
renderContent() {
const {children} = this.props;
/***
Decide base on the props what to do.
DO NOT try to sync the state, that might open the door for πŸ›πŸœπŸœπŸœ (BUGS)
***/
if (this.isControlled()) {
return this.props.isCollapsed ? null : children;
}
return this.state.startCollapsed ? null : children;
}
render() {
const {handler, children} = this.props
return (
<div className="collapsible">
<div>{handler}<button onClick={() => this.onClick()}>toggle</button></div>
<div>{this.renderContent()}</div>
</div>
)
}
}
// Stateless functional components
// The pattern:
// This pattern behave as a snapshot of your UI depending of the props pass down.
// Put in simple is just a function.
// When to use it:
// Good to use for dumb component that only care about presentation
// as example would be a placeholders which will wrap a children components
// in a specific location in your app.
// Thumb up rule: The component no needs state or react cycles
// pros:
// no class declaration
// no need of this keyword that can confuse new comer into javascript world
// easier to detect code smell because is a function
// works with Context
// works with ref
// cons:
// no react cycles at all
// example.
import React from 'react'
import './FooterStateless.css'
// Stateless Component
// Footer will act as a placeholder with a specific style
const Footer = (props) => {
const {children} = props;
return (
<div className="footer">
{children}
</div>
)
}
export default Footer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment