{"id":13701122,"url":"https://github.com/chantastic/reactpatterns","last_synced_at":"2025-04-08T08:15:17.984Z","repository":{"id":37706223,"uuid":"66016792","full_name":"chantastic/reactpatterns","owner":"chantastic","description":"Patterns for React Developers","archived":false,"fork":false,"pushed_at":"2022-01-15T01:23:45.000Z","size":175,"stargazers_count":1729,"open_issues_count":7,"forks_count":99,"subscribers_count":60,"default_branch":"master","last_synced_at":"2025-04-01T05:36:00.639Z","etag":null,"topics":["component","frontend","javascript","patterns","react","react-native","react-patterns"],"latest_commit_sha":null,"homepage":"http://reactpatterns.com","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chantastic.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-18T17:20:27.000Z","updated_at":"2025-03-13T03:36:29.000Z","dependencies_parsed_at":"2022-08-08T21:16:17.143Z","dependency_job_id":null,"html_url":"https://github.com/chantastic/reactpatterns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freactpatterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freactpatterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freactpatterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freactpatterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chantastic","download_url":"https://codeload.github.com/chantastic/reactpatterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801175,"owners_count":20998339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","frontend","javascript","patterns","react","react-native","react-patterns"],"created_at":"2024-08-02T20:01:18.550Z","updated_at":"2025-04-08T08:15:17.968Z","avatar_url":"https://github.com/chantastic.png","language":"HTML","readme":"## Contents\n\n* [Stateless function](#stateless-function)\n* [JSX spread attributes](#jsx-spread-attributes)\n* [Destructuring arguments](#destructuring-arguments)\n* [Conditional rendering](#conditional-rendering)\n* [Children types](#children-types)\n* [Array as children](#array-as-children)\n* [Function as children](#function-as-children)\n* [Render callback](#render-callback)\n* [Children pass-through](#children-pass-through)\n* [Proxy component](#proxy-component)\n* [Style component](#style-component)\n* [Event switch](#event-switch)\n* [Layout component](#layout-component)\n* [Container component](#container-component)\n* [Higher-order component](#higher-order-component)\n* [State hoisting](#state-hoisting)\n* [Controlled input](#controlled-input)\n\n## Stateless function\n\n[Stateless functions](https://facebook.github.io/react/docs/components-and-props.html) are a brilliant way to define highly reusable components. They don't hold `state`; they're just functions.\n\n```js\nconst Greeting = () =\u003e \u003cdiv\u003eHi there!\u003c/div\u003e\n```\n\nThey get passed `props` and `context`.\n\n```js\nconst Greeting = (props, context) =\u003e\n  \u003cdiv style={{color: context.color}}\u003eHi {props.name}!\u003c/div\u003e\n```\n\nThey can define local variables, where a function block is used.\n\n```js\nconst Greeting = (props, context) =\u003e {\n  const style = {\n    fontWeight: \"bold\",\n    color: context.color,\n  }\n\n  return \u003cdiv style={style}\u003e{props.name}\u003c/div\u003e\n}\n```\n\nBut you could get the same result by using other functions.\n\n```js\nconst getStyle = context =\u003e ({\n  fontWeight: \"bold\",\n  color: context.color,\n})\n\nconst Greeting = (props, context) =\u003e\n  \u003cdiv style={getStyle(context)}\u003e{props.name}\u003c/div\u003e\n```\n\nThey can have defined `defaultProps`, `propTypes` and `contextTypes`.\n\n```js\nGreeting.propTypes = {\n  name: PropTypes.string.isRequired\n}\nGreeting.defaultProps = {\n  name: \"Guest\"\n}\nGreeting.contextTypes = {\n  color: PropTypes.string\n}\n```\n\n\n## JSX spread attributes\n\nSpread Attributes is a JSX feature. It's syntactic sugar for passing all of an object's properties as JSX attributes.\n\nThese two examples are equivalent.\n```js\n// props written as attributes\n\u003cmain className=\"main\" role=\"main\"\u003e{children}\u003c/main\u003e\n\n// props \"spread\" from object\n\u003cmain {...{className: \"main\", role: \"main\", children}} /\u003e\n```\n\nUse this to forward `props` to underlying components.\n\n```js\nconst FancyDiv = props =\u003e\n  \u003cdiv className=\"fancy\" {...props} /\u003e\n```\n\nNow, I can expect `FancyDiv` to add the attributes it's concerned with as well as those it's not.\n\n```js\n\u003cFancyDiv data-id=\"my-fancy-div\"\u003eSo Fancy\u003c/FancyDiv\u003e\n\n// output: \u003cdiv class=\"fancy\" data-id=\"my-fancy-div\"\u003eSo Fancy\u003c/div\u003e\n```\n\nKeep in mind that order matters. If `props.className` is defined, it'll clobber the `className` defined by `FancyDiv`\n\n```js\n\u003cFancyDiv className=\"my-fancy-div\" /\u003e\n\n// output: \u003cdiv className=\"my-fancy-div\"\u003e\u003c/div\u003e\n```\n\nWe can make `FancyDiv`s className always \"win\" by placing it after the spread props `({...props})`.\n\n```js\n// my `className` clobbers your `className`\nconst FancyDiv = props =\u003e\n  \u003cdiv {...props} className=\"fancy\" /\u003e\n```\n\nYou 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.\n\n```js\nconst FancyDiv = ({ className, ...props }) =\u003e\n  \u003cdiv\n    className={[\"fancy\", className].join(' ')}\n    {...props}\n  /\u003e\n```\n\n\n## destructuring arguments\n\n[Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) is an ES2015 feature. It pairs nicely with `props` in Stateless Functions.\n\nThese examples are equivalent.\n```js\nconst Greeting = props =\u003e \u003cdiv\u003eHi {props.name}!\u003c/div\u003e\n\nconst Greeting = ({ name }) =\u003e \u003cdiv\u003eHi {name}!\u003c/div\u003e\n```\n\nThe [rest parameter syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) (`...`) allows you to collect all the remaining properties in a new object.\n\n```js\nconst Greeting = ({ name, ...props }) =\u003e\n  \u003cdiv\u003eHi {name}!\u003c/div\u003e\n```\n\nIn turn, this object can use [JSX Spread Attributes](#jsx-spread-attributes) to forward `props` to the composed component.\n\n```js\nconst Greeting = ({ name, ...props }) =\u003e\n  \u003cdiv {...props}\u003eHi {name}!\u003c/div\u003e\n```\n\nAvoid forwarding non-DOM `props` to composed components. Destructuring makes this very easy because you can create a new `props` object **without** component-specific `props`.\n\n\n## conditional rendering\n\nYou can't use regular if/else conditions inside a component definition. [The conditional (ternary) operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) is your friend.\n\n`if`\n\n```js\n{condition \u0026\u0026 \u003cspan\u003eRendered when `truthy`\u003c/span\u003e }\n```\n\n`unless`\n\n```js\n{condition || \u003cspan\u003eRendered when `falsey`\u003c/span\u003e }\n```\n\n`if-else` (tidy one-liners)\n\n```js\n{condition\n  ? \u003cspan\u003eRendered when `truthy`\u003c/span\u003e\n  : \u003cspan\u003eRendered when `falsey`\u003c/span\u003e\n}\n```\n\n`if-else` (big blocks)\n\n```js\n{condition ? (\n  \u003cspan\u003e\n    Rendered when `truthy`\n  \u003c/span\u003e\n) : (\n  \u003cspan\u003e\n    Rendered when `falsey`\n  \u003c/span\u003e\n)}\n```\n\n\n## Children types\n\nReact can render `children` of many types. In most cases it's either an `array` or a `string`.\n\n`string`\n\n```js\n\u003cdiv\u003e\n  Hello World!\n\u003c/div\u003e\n```\n\n`array`\n\n```js\n\u003cdiv\u003e\n  {[\"Hello \", \u003cspan\u003eWorld\u003c/span\u003e, \"!\"]}\n\u003c/div\u003e\n```\n\nFunctions may be used as children. However, it requires [coordination with the parent component](#render-callback) to be useful.\n\n`function`\n\n```js\n\u003cdiv\u003e\n  {(() =\u003e { return \"hello world!\"})()}\n\u003c/div\u003e\n```\n\n\n## Array as children\n\nProviding an array as `children` is a very common. It's how lists are drawn in React.\n\nWe use `map()` to create an array of React Elements for every value in the array.\n\n```js\n\u003cul\u003e\n  {[\"first\", \"second\"].map((item) =\u003e (\n    \u003cli\u003e{item}\u003c/li\u003e\n  ))}\n\u003c/ul\u003e\n```\n\nThat's equivalent to providing a literal `array`.\n\n```js\n\u003cul\u003e\n  {[\n    \u003cli\u003efirst\u003c/li\u003e,\n    \u003cli\u003esecond\u003c/li\u003e,\n  ]}\n\u003c/ul\u003e\n```\n\nThis pattern can be combined with destructuring, JSX Spread Attributes, and other components, for some serious terseness.\n\n```js\n\u003cdiv\u003e\n  {arrayOfMessageObjects.map(({ id, ...message }) =\u003e\n    \u003cMessage key={id} {...message} /\u003e\n  )}\n\u003c/div\u003e\n```\n\n\n## Function as children\n\nUsing a function as `children` isn't inherently useful.\n\n```js\n\u003cdiv\u003e{() =\u003e { return \"hello world!\"}()}\u003c/div\u003e\n```\n\nHowever, it can be used in component authoring for some serious power. This technique is commonly referred to as `render callbacks`.\n\nThis is a powerful technique used by libraries like [ReactMotion](https://github.com/chenglou/react-motion). When applied, rendering logic can be kept in the owner component, instead of being delegated.\n\nSee [Render callbacks](#render-callback), for more details.\n\n## Render callback\n\nHere's a component that uses a Render callback. It's not useful, but it's an easy illustration to start with.\n\n```js\nconst Width = ({ children }) =\u003e children(500)\n```\n\nThe component calls `children` as a function, with some number of arguments. Here, it's the number `500`.\n\nTo use this component, we give it a [function as `children`](#function-as-children).\n\n```js\n\u003cWidth\u003e\n  {width =\u003e \u003cdiv\u003ewindow is {width}\u003c/div\u003e}\n\u003c/Width\u003e\n```\n\nWe get this output.\n\n```js\n\u003cdiv\u003ewindow is 500\u003c/div\u003e\n```\n\nWith this setup, we can use this `width` to make rendering decisions.\n\n```js\n\u003cWidth\u003e\n  {width =\u003e\n    width \u003e 600\n      ? \u003cdiv\u003emin-width requirement met!\u003c/div\u003e\n      : null\n  }\n\u003c/Width\u003e\n```\n\nIf we plan to use this condition a lot, we can define another components to encapsulate the reused logic.\n\n```js\nconst MinWidth = ({ width: minWidth, children }) =\u003e\n  \u003cWidth\u003e\n    {width =\u003e\n      width \u003e minWidth\n        ? children\n        : null\n    }\n  \u003c/Width\u003e\n```\n\n\nObviously a static `Width` component isn't useful but one that watches the browser window is. Here's a sample implementation.\n\n```js\nclass WindowWidth extends React.Component {\n  constructor() {\n    super()\n    this.state = { width: 0 }\n  }\n\n  componentDidMount() {\n    this.setState(\n      {width: window.innerWidth},\n      window.addEventListener(\n        \"resize\",\n        ({ target }) =\u003e\n          this.setState({width: target.innerWidth})\n      )\n    )\n  }\n\n  render() {\n    return this.props.children(this.state.width)\n  }\n}\n```\n\nMany developers favor [Higher Order Components](#higher-order-component) for this type of functionality. It's a matter of preference.\n\n\n## Children pass-through\n\nThere are times you'll need to wrap a stateless function with lifecycle events.\nWhile we want to wrap component functionality around other components, we don't want to introduce extraneous DOM nodes.\nIn some apps, this might brake styling.\n\nWe use the function `React.Children.only`.\n`only` allows us to return `this.props.children` __if__ there is only one child.\nOtherwise, it throws an error.\n\n```js\nclass SomeLifeCycleWrapper extends React.Component {\n  componentDidMount() {\n    console.log(\"I mounted but have no DOM.\")\n  }\n\n  render() {\n    return React.Children.only(this.props.children)\n  }\n}\n```\n\nIn cases where you're working with `state` or `context`, prefer [higher-order components](#higher-order-component) or [render callbacks](#render-callback).\n\n\n## Proxy component\n\n*(I'm not sure if this name makes sense)*\n\nButtons are everywhere in web apps. And every one of them must have the `type` attribute set to \"button\".\n\n```js\n\u003cbutton type=\"button\"\u003e\n```\n\nWriting this attribute hundreds of times is error prone. We can write a higher level component to proxy `props` to a lower-level `button` component.\n\n```js\nconst Button = props =\u003e\n  \u003cbutton type=\"button\" {...props}\u003e\n```\n\nWe can use `Button` in place of `button` and ensure that the `type` attribute is consistently applied everywhere.\n\n```js\n\u003cButton /\u003e\n// \u003cbutton type=\"button\"\u003e\u003cbutton\u003e\n\n\u003cButton className=\"CTA\"\u003eSend Money\u003c/Button\u003e\n// \u003cbutton type=\"button\" class=\"CTA\"\u003eSend Money\u003c/button\u003e\n```\n\n## Style component\n\nThis is a [Proxy component](#proxy-component) applied to the practices of style.\n\nSay we have a button. It uses classes to be styled as a \"primary\" button.\n\n```js\n\u003cbutton type=\"button\" className=\"btn btn-primary\"\u003e\n```\n\nWe can generate this output using a couple single-purpose components.\n\n```js\nimport classnames from 'classnames'\n\nconst PrimaryBtn = props =\u003e\n  \u003cBtn {...props} primary /\u003e\n\nconst Btn = ({ className, primary, ...props }) =\u003e\n  \u003cbutton\n    type=\"button\"\n    className={classnames(\n      \"btn\",\n      primary \u0026\u0026 \"btn-primary\",\n      className\n    )}\n    {...props}\n  /\u003e\n```\n\nIt can help to visualize this.\n\n```js\nPrimaryBtn()\n  ↳ Btn({primary: true})\n    ↳ Button({className: \"btn btn-primary\"}, type: \"button\"})\n      ↳ '\u003cbutton type=\"button\" class=\"btn btn-primary\"\u003e\u003c/button\u003e'\n```\n\nUsing these components, all of these result in the same output.\n```js\n\u003cPrimaryBtn /\u003e\n\u003cBtn primary /\u003e\n\u003cbutton type=\"button\" className=\"btn btn-primary\" /\u003e\n```\n\nThis can be a huge boon to style maintenance. It isolates all concerns of style to a single component.\n\n## Event switch\n\n\nWhen writing event handlers it's common to adopt the `handle{eventName}` naming convention.\n\n```js\nhandleClick(e) { /* do something */ }\n```\n\nFor components that handle several event types, these function names can be repetitive. The names themselves might not provide much value, as they simply proxy to other actions/functions.\n\n```js\nhandleClick() { require(\"./actions/doStuff\")(/* action stuff */) }\nhandleMouseEnter() { this.setState({ hovered: true }) }\nhandleMouseLeave() { this.setState({ hovered: false }) }\n```\n\nConsider writing a single event handler for your component and switching on `event.type`.\n\n```js\nhandleEvent({type}) {\n  switch(type) {\n    case \"click\":\n      return require(\"./actions/doStuff\")(/* action dates */)\n    case \"mouseenter\":\n      return this.setState({ hovered: true })\n    case \"mouseleave\":\n      return this.setState({ hovered: false })\n    default:\n      return console.warn(`No case for event type \"${type}\"`)\n  }\n}\n```\n\nAlternatively, for simple components, you can call imported actions/functions directly from components, using arrow functions.\n\n```js\n\u003cdiv onClick={() =\u003e someImportedAction({ action: \"DO_STUFF\" })}\n```\n\nDon't fret about performance optimizations until you have problems. Seriously don't.\n\n\n## Layout component\n\n\nLayout components result in some form of static DOM element. It might not need to update frequently, if ever.\n\nConsider a component that renders two `children` side-by-side.\n\n```js\n\u003cHorizontalSplit\n  leftSide={\u003cSomeSmartComponent /\u003e}\n  rightSide={\u003cAnotherSmartComponent /\u003e}\n/\u003e\n```\n\nWe can aggressively optimize this component.\n\nWhile `HorizontalSplit` will be `parent` to both components, it will never be their `owner`. We can tell it to update never, without interrupting the lifecycle of the components inside.\n\n```js\nclass HorizontalSplit extends React.Component {\n  shouldComponentUpdate() {\n    return false\n  }\n\n  render() {\n    \u003cFlexContainer\u003e\n      \u003cdiv\u003e{this.props.leftSide}\u003c/div\u003e\n      \u003cdiv\u003e{this.props.rightSide}\u003c/div\u003e\n    \u003c/FlexContainer\u003e\n  }\n}\n```\n\n\n## Container component\n\n\"A container does data fetching and then renders its corresponding sub-component. That’s it.\"\u0026mdash;[Jason Bonta](https://twitter.com/jasonbonta)\n\nGiven this reusable `CommentList` component.\n\n```js\nconst CommentList = ({ comments }) =\u003e\n  \u003cul\u003e\n    {comments.map(comment =\u003e\n      \u003cli\u003e{comment.body}-{comment.author}\u003c/li\u003e\n    )}\n  \u003c/ul\u003e\n```\n\nWe can create a new component responsible for fetching data and rendering the stateless `CommentList` component.\n\n```js\nclass CommentListContainer extends React.Component {\n  constructor() {\n    super()\n    this.state = { comments: [] }\n  }\n\n  componentDidMount() {\n    $.ajax({\n      url: \"/my-comments.json\",\n      dataType: 'json',\n      success: comments =\u003e\n        this.setState({comments: comments});\n    })\n  }\n\n  render() {\n    return \u003cCommentList comments={this.state.comments} /\u003e\n  }\n}\n```\n\nWe can write different containers for different application contexts.\n\n\n## Higher-order component\n\nA [higher-order function](https://en.wikipedia.org/wiki/Higher-order_function) is a function that takes and/or returns a function. It's not more complicated than that. So, what's a higher-order component?\n\nIf you're already using [container components](#container-component), these are just generic containers, wrapped up in a function.\n\nLet's start with our stateless `Greeting` component.\n\n```js\nconst Greeting = ({ name }) =\u003e {\n  if (!name) { return \u003cdiv\u003eConnecting...\u003c/div\u003e }\n\n  return \u003cdiv\u003eHi {name}!\u003c/div\u003e\n}\n```\n\nIf it gets `props.name`, it's gonna render that data. Otherwise it'll say that it's \"Connecting...\". Now for the the higher-order bit.\n\n```js\nconst Connect = ComposedComponent =\u003e\n  class extends React.Component {\n    constructor() {\n      super()\n      this.state = { name: \"\" }\n    }\n\n    componentDidMount() {\n      // this would fetch or connect to a store\n      this.setState({ name: \"Michael\" })\n    }\n\n    render() {\n      return (\n        \u003cComposedComponent\n          {...this.props}\n          name={this.state.name}\n        /\u003e\n      )\n    }\n  }\n```\n\nThis is just a function that returns component that renders the component we passed as an argument.\n\nLast step, we need to wrap our our `Greeting` component in `Connect`.\n\n```js\nconst ConnectedMyComponent = Connect(Greeting)\n```\n\nThis is a powerful pattern for providing fetching and providing data to any number of [stateless function components](#stateless-function).\n\n## State hoisting\n[Stateless functions](#stateless-function) don't hold state (as the name implies).\n\nEvents are changes in state.\nTheir data needs to be passed to stateful [container components](#container-component) parents.\n\nThis is called \"state hoisting\".\nIt's accomplished by passing a callback from a container component to a child component.\n\n```js\nclass NameContainer extends React.Component {\n  render() {\n    return \u003cName onChange={newName =\u003e alert(newName)} /\u003e\n  }\n}\n\nconst Name = ({ onChange }) =\u003e\n  \u003cinput onChange={e =\u003e onChange(e.target.value)} /\u003e\n```\n\n`Name` receives an `onChange` callback from `NameContainer` and calls on events.\n\nThe `alert` above makes for a terse demo but it's not changing state.\nLet's change the internal state of `NameContainer`.\n\n```js\nclass NameContainer extends React.Component {\n  constructor() {\n    super()\n    this.state = {name: \"\"}\n  }\n\n  render() {\n    return \u003cName onChange={newName =\u003e this.setState({name: newName})} /\u003e\n  }\n}\n```\n\nThe state is _hoisted_ to the container, by the provided callback, where it's used to update local state.\nThis sets a nice clear boundary and maximizes the re-usability of stateless function.\n\nThis pattern isn't limited to stateless functions.\nBecause stateless function don't have lifecycle events,\nyou'll use this pattern with component classes as well.\n\n*[Controlled input](#controlled-input) is an important pattern to know for use with state hoisting*\n\n*(It's best to process the event object on the stateful component)*\n\n\n## Controlled input\nIt's hard to talk about controlled inputs in the abstract.\nLet's start with an uncontrolled (normal) input and go from there.\n\n```js\n\u003cinput type=\"text\" /\u003e\n```\n\nWhen you fiddle with this input in the browser, you see your changes.\nThis is normal.\n\nA controlled input disallows the DOM mutations that make this possible.\nYou set the `value` of the input in component-land and it doesn't change in DOM-land.\n\n```js\n\u003cinput type=\"text\" value=\"This won't change. Try it.\" /\u003e\n```\n\nObviously static inputs aren't very useful to your users.\nSo, we derive a `value` from state.\n\n```js\nclass ControlledNameInput extends React.Component {\n  constructor() {\n    super()\n    this.state = {name: \"\"}\n  }\n\n  render() {\n    return \u003cinput type=\"text\" value={this.state.name} /\u003e\n  }\n}\n```\n\nThen, changing the input is a matter of changing component state.\n\n```js\n    return (\n      \u003cinput\n        value={this.state.name}\n        onChange={e =\u003e this.setState({ name: e.target.value })}\n      /\u003e\n    )\n```\n\nThis is a controlled input.\nIt only updates the DOM when state has changed in our component.\nThis is invaluable when creating consistent UIs.\n\n*If you're using [stateless functions](#stateless-function) for form elements,\nread about using [state hoisting](#state-hoisting) to move new state up the component tree.*\n","funding_links":[],"categories":["HTML"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchantastic%2Freactpatterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchantastic%2Freactpatterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchantastic%2Freactpatterns/lists"}