Last active
May 10, 2022 01:01
-
-
Save nahumzs/e5429c9b95db73a0540159803c9dd433 to your computer and use it in GitHub Desktop.
React patterns π»π¦
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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> | |
) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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