[React] Compound Pattern
Source : https://javascriptpatterns.vercel.app/patterns/react-patterns/compound-pattern
A compound compoennt usage looks like this:
import React from "react";
import { FlyOut } from "./FlyOut";
export default function SearchInput() {
return (
<FlyOut>
<FlyOut.Input placeholder="Enter an address, city, or ZIP code" />
<FlyOut.List>
<FlyOut.ListItem value="San Francisco, CA">
San Francisco, CA
</FlyOut.ListItem>
<FlyOut.ListItem value="Seattle, WA">Seattle, WA</FlyOut.ListItem>
<FlyOut.ListItem value="Austin, TX">Austin, TX</FlyOut.ListItem>
<FlyOut.ListItem value="Miami, FL">Miami, FL</FlyOut.ListItem>
<FlyOut.ListItem value="Boulder, CO">Boulder, CO</FlyOut.ListItem>
</FlyOut.List>
</FlyOut>
);
}
We can implement the Compound pattern using either a Provider, or React.Children.map
.
Provider (preferred)
The FlyOut
compound component consists of:
FlyoutContext
to keep track of the visbility state ofFlyOut
Input
to toggle theFlyOut
'sList
component's visibilityList
to render theFlyOut
'sListItems
sListItem
that gets rendered within theList
.
const FlyOutContext = React.createContext();
export function FlyOut(props) {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");
const toggle = React.useCallback(() => setOpen((state) => !state), []);
return (
<FlyOutContext.Provider value={{ open, toggle, value, setValue }}>
<div>{props.children}</div>
</FlyOutContext.Provider>
);
}
function Input(props) {
const { value, toggle } = React.useContext(FlyOutContext);
return <input onFocus={toggle} onBlur={toggle} value={value} {...props} />;
}
function List({ children }) {
const { open } = React.useContext(FlyOutContext);
return open && <ul>{children}</ul>;
}
function ListItem({ children, value }) {
const { setValue } = React.useContext(FlyOutContext);
return <li onMouseDown={() => setValue(value)}>{children}</li>;
}
FlyOut.Input = Input;
FlyOut.List = List;
FlyOut.ListItem = ListItem;
React.Children.map
export function FlyOut(props) {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");
const toggle = React.useCallback(() => setOpen((state) => !state), []);
return (
<div>
{React.Children.map(props.children, (child) =>
React.cloneElement(child, { open, toggle, value, setValue })
)}
</div>
);
}
function Input(props) {
const { value, toggle } = React.useContext(FlyOutContext);
return <input onFocus={toggle} onBlur={toggle} value={value} {...props} />;
}
function List({ children }) {
const { open } = React.useContext(FlyOutContext);
return open && <ul>{children}</ul>;
}
function ListItem({ children, value }) {
const { setValue } = React.useContext(FlyOutContext);
return <li onMouseDown={() => setValue(value)}>{children}</li>;
}
FlyOut.Input = Input;
FlyOut.List = List;
FlyOut.ListItem = ListItem;
分类:
React
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2021-08-26 [CSS 3] Solved: DOM element which is visible but not clickable: pointer-events
2021-08-26 [Cloud Architect] 2. Resiliency
2020-08-26 [Machine Learning] Cost Function for Logistic Regression Model
2018-08-26 [Typescript Kaop-ts] Use AOP in Vue Components with TypeScript and Kaop-ts
2015-08-26 [React] React Fundamentals: JSX Deep Dive
2015-08-26 [React] React Fundamentals: Build a JSX Live Compiler