Reactpatterns
Patterns for React Developers
Install / Use
/learn @chantastic/ReactpatternsREADME
Contents
- Stateless function
- JSX spread attributes
- Destructuring arguments
- Conditional rendering
- Children types
- Array as children
- Function as children
- Render callback
- Children pass-through
- Proxy component
- Style component
- Event switch
- Layout component
- Container component
- Higher-order component
- State hoisting
- Controlled input
Stateless function
Stateless functions are a brilliant way to define highly reusable components. They don't hold state; they're just functions.
const Greeting = () => <div>Hi there!</div>
They get passed props and context.
const Greeting = (props, context) =>
<div style={{color: context.color}}>Hi {props.name}!</div>
They can define local variables, where a function block is used.
const Greeting = (props, context) => {
const style = {
fontWeight: "bold",
color: context.color,
}
return <div style={style}>{props.name}</div>
}
But you could get the same result by using other functions.
const getStyle = context => ({
fontWeight: "bold",
color: context.color,
})
const Greeting = (props, context) =>
<div style={getStyle(context)}>{props.name}</div>
They can have defined defaultProps, propTypes and contextTypes.
Greeting.propTypes = {
name: PropTypes.string.isRequired
}
Greeting.defaultProps = {
name: "Guest"
}
Greeting.contextTypes = {
color: PropTypes.string
}
JSX spread attributes
Spread Attributes is a JSX feature. It's syntactic sugar for passing all of an object's properties as JSX attributes.
These two examples are equivalent.
// props written as attributes
<main className="main" role="main">{children}</main>
// props "spread" from object
<main {...{className: "main", role: "main", children}} />
Use this to forward props to underlying components.
const FancyDiv = props =>
<div className="fancy" {...props} />
Now, I can expect FancyDiv to add the attributes it's concerned with as well as those it's not.
<FancyDiv data-id="my-fancy-div">So Fancy</FancyDiv>
// output: <div class="fancy" data-id="my-fancy-div">So Fancy</div>
Keep in mind that order matters. If props.className is defined, it'll clobber the className defined by FancyDiv
<FancyDiv className="my-fancy-div" />
// output: <div className="my-fancy-div"></div>
We can make FancyDivs className always "win" by placing it after the spread props ({...props}).
// my `className` clobbers your `className`
const FancyDiv = props =>
<div {...props} className="fancy" />
You should handle these types of props gracefully. In this case, I'll merge the author's props.className with the className needed to style my component.
const FancyDiv = ({ className, ...props }) =>
<div
className={["fancy", className].join(' ')}
{...props}
/>
destructuring arguments
Destructuring assignment is an ES2015 feature. It pairs nicely with props in Stateless Functions.
These examples are equivalent.
const Greeting = props => <div>Hi {props.name}!</div>
const Greeting = ({ name }) => <div>Hi {name}!</div>
The rest parameter syntax (...) allows you to collect all the remaining properties in a new object.
const Greeting = ({ name, ...props }) =>
<div>Hi {name}!</div>
In turn, this object can use JSX Spread Attributes to forward props to the composed component.
const Greeting = ({ name, ...props }) =>
<div {...props}>Hi {name}!</div>
Avoid forwarding non-DOM props to composed components. Destructuring makes this very easy because you can create a new props object without component-specific props.
conditional rendering
You can't use regular if/else conditions inside a component definition. The conditional (ternary) operator is your friend.
if
{condition && <span>Rendered when `truthy`</span> }
unless
{condition || <span>Rendered when `falsey`</span> }
if-else (tidy one-liners)
{condition
? <span>Rendered when `truthy`</span>
: <span>Rendered when `falsey`</span>
}
if-else (big blocks)
{condition ? (
<span>
Rendered when `truthy`
</span>
) : (
<span>
Rendered when `falsey`
</span>
)}
Children types
React can render children of many types. In most cases it's either an array or a string.
string
<div>
Hello World!
</div>
array
<div>
{["Hello ", <span>World</span>, "!"]}
</div>
Functions may be used as children. However, it requires coordination with the parent component to be useful.
function
<div>
{(() => { return "hello world!"})()}
</div>
Array as children
Providing an array as children is a very common. It's how lists are drawn in React.
We use map() to create an array of React Elements for every value in the array.
<ul>
{["first", "second"].map((item) => (
<li>{item}</li>
))}
</ul>
That's equivalent to providing a literal array.
<ul>
{[
<li>first</li>,
<li>second</li>,
]}
</ul>
This pattern can be combined with destructuring, JSX Spread Attributes, and other components, for some serious terseness.
<div>
{arrayOfMessageObjects.map(({ id, ...message }) =>
<Message key={id} {...message} />
)}
</div>
Function as children
Using a function as children isn't inherently useful.
<div>{() => { return "hello world!"}()}</div>
However, it can be used in component authoring for some serious power. This technique is commonly referred to as render callbacks.
This is a powerful technique used by libraries like ReactMotion. When applied, rendering logic can be kept in the owner component, instead of being delegated.
See Render callbacks, for more details.
Render callback
Here's a component that uses a Render callback. It's not useful, but it's an easy illustration to start with.
const Width = ({ children }) => children(500)
The component calls children as a function, with some number of arguments. Here, it's the number 500.
To use this component, we give it a function as children.
<Width>
{width => <div>window is {width}</div>}
</Width>
We get this output.
<div>window is 500</div>
With this setup, we can use this width to make rendering decisions.
<Width>
{width =>
width > 600
? <div>min-width requirement met!</div>
: null
}
</Width>
If we plan to use this condition a lot, we can define another components to encapsulate the reused logic.
const MinWidth = ({ width: minWidth, children }) =>
<Width>
{width =>
width > minWidth
? children
: null
}
</Width>
Obviously a static Width component isn't useful but one that watches the browser window is. Here's a sample implementation.
class WindowWidth extends React.Component {
constructor() {
super()
this.state = { width: 0 }
}
componentDidMount() {
this.setState(
{width: window.innerWidth},
window.addEventListener(
"resize",
({ target }) =>
this.setState({width: target.innerWidth})
)
)
}
render() {
return this.props.children(this.state.width)
}
}
Many developers favor Higher Order Components for this type of functionality. It's a matter of preference.
Children pass-through
There are times you'll need to wrap a stateless function with lifecycle events. While we want to wrap component functionality around other components, we don't want to introduce extraneous DOM nodes. In some apps, this might brake styling.
We use the function React.Children.only.
only allows us to return this.props.children if there is only one child.
Otherwise, it throws an error.
class SomeLifeCycleWrapper extends React.Component {
componentDidMount() {
console.log("I mounted but have no DOM.")
}
render() {
return React.Children.only(this.props.children)
}
}
In cases where you're working with state or context, prefer higher-order components or render callbacks.
Proxy component
(I'm not sure if this name makes sense)
Buttons are everywhere in web apps. And every one of them must have the type attribute set to "button".
<button type="button">
Writing this attribute hundreds of times is error prone. We can write a higher level component to proxy props to a lower-level button component.
const Button = props =>
<button type="button" {...props}>
We can use Button in place of button and ensure that the type attribute is consistently applied everywhere.
<Button />
// <button type="button"><button>
<Button className="CTA">Send Money</Button>
// <button type="button" class="CTA">Send Money</button>
Style component
This is a Proxy component applied to the practices of style.
Say we have a button. It uses classes to be styled as a "primary" butto
Related Skills
bluebubbles
350.8kUse when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles".
node-connect
350.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
slack
350.8kUse when you need to control Slack from OpenClaw via the slack tool, including reacting to messages or pinning/unpinning items in Slack channels or DMs.
frontend-design
110.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
