This architecture is divisible into three components, Pure Components, Interfaces and Logic Hooks. It is a variant on the Presentational and Container Components pattern described by Dan Abramov, now considering the existence of Hooks.
Pure Components
Interface
Logic Hook
Interfaces are mainly concerned with how information should be shared between Logic Hooks and with Pure Components. Interfaces receive functions and values provided by Logic Hooks and share them with other Logic Hooks or pass them as props to Pure Components.
Logic Hooks are similar to Container Components. Pure Components are similar to Presentational Components. But they differ on some points.
Comparison
Presentational Components and Pure Components
From Dan's post:
"My presentational components:
- Are concerned with how things look.
- May contain both presentational and container components** inside, and usually have some DOM markup and styles of their own.
- Often allow containment via this.props.children.
- Have no dependencies on the rest of the app, such as Flux actions or stores.
- Don't specify how the data is loaded or mutated.
- Receive data and callbacks exclusively via props.
- Rarely have their own state (when they do, it's UI state rather than data).
- Are written as functional components unless they need state, lifecycle hooks, or performance optimizations.
- Examples: Page, Sidebar, Story, UserInfo, List."
My Pure Components:
- Same ("Are concerned with how things look.").
- May contain other Pure Components, markup, and styles.
- Same ("Often allow containment via this.props.children.") props.children.
- Same ("Have no dependencies on the rest of the app, such as Flux actions or stores.").
- Same ("Don't specify how the data is loaded or mutated.").
- Same ("Receive data and callbacks exclusively via props.").
- Don't have their own state. They should receive, as props, a local state provided by a Logic Hook through an Interface.
- Are written as functional components.
- Same ("Examples: Page, Sidebar, Story, UserInfo, List.").
Container Components and Logic Hooks
From Dan's post:
"My container components:
- Are concerned with how things work.
- May contain both presentational and container components** inside but usually don't have any DOM markup of their own except for some wrapping divs, and never have any styles.
- Provide the data and behavior to presentational or other container components.
- Call Flux actions and provide these as callbacks to the presentational components.
- Are often stateful, as they tend to serve as data sources.
- Are usually generated using higher order components such as connect()from React Redux, createContainer() from Relay, or Container.create()from Flux Utils, rather than written by hand.
- Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList."
My Logic Hooks:
- Same ("Are concerned with how things work.").
- Shouldn't contain other components, markup or styles.
- Provide the data and behavior to Interfaces.
- Call Flux actions and provide these as callbacks to Interfaces.
- Same ("Are often stateful, as they tend to serve as data sources.").
- n/a ("Are usually generated using higher order components such as connect()…").
- Examples: useUser, useFollowers, useStory, useFollowed.
Just like the Presentational and Container Component pattern, this separation makes it easier to replace or delete code. If you wanted to replace your state container, you would need to update your Logic Hooks, but not your Interfaces or Pure Components. But it is particularly useful if your application has different UI flows, hence the name "Interface". For example, you could use the same Logic Hooks for a React and React Native application with different Interfaces. These Interfaces would receive information from the same Logic Hooks, and accommodate Pure Components in distinct ways.
Full example
Top comments (7)
Nit: you used the list code two times.
otherwise good post, while I wouldn't use the name "interface" for this concept, because it could be confused also I'd prefer a Redux-less solution, probably created with
useReducer
or somethingThanks! I chose the name 'Interface' because it's the layer that connects the other two components and it represents the user interface. I'd appreciate any suggestions for a better name. I used Redux to show the responsibility of the Logic Hook, but it could be replaced by useReducer or anything else.
Maybe facade? That's a good pattern name that does similar things here.
thanks for introducing a fresh way to have state in react app. I like the idea to have logic hooks so it looks cleaner
Thanks!
Love the separation of concerns. However, I wonder what are the edge cases with this pattern.
Thanks! Not sure about edge cases, they may appear over time.