-
Notifications
You must be signed in to change notification settings - Fork 562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating light components #259
Open
Nefcanto
wants to merge
1
commit into
reactjs:main
Choose a base branch
from
Nefcanto:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
- Start Date: (2024-10-6) | ||
- RFC PR: (leave this empty) | ||
- React Issue: (leave this empty) | ||
|
||
# Summary | ||
|
||
React at first had class components. Creating a class component was hard. So it introduced function components. | ||
Function components were easier to create. They were more readable. They had less boilerplate. | ||
Then server components came into the scene. | ||
|
||
Now I would like to propose *light components*. They are simple valid JSX variables or constants. They do not have props and they do not have states. They are just a simple JSX bundle. | ||
|
||
# Basic example | ||
|
||
``` | ||
const Contacts = <div> | ||
<div>some phone number</div> | ||
<div>some email</div> | ||
</div> | ||
|
||
<Contacts /> | ||
``` | ||
|
||
# Motivation | ||
|
||
It's all about unnecessary boilerplate. Our team has built an SPL (software product line). The panel is built using React. | ||
We minimize the boilerplate as much as we can. The reduced boilerplate adds direct business value to us (enhanced maintainability, lower learning curve, faster time-to-market). | ||
|
||
One aspect of the boilerplate is to be forced to add at least two parentheses and a lambda (4 characters) to turn a JSX constant into a function component: | ||
|
||
``` | ||
const Contacts = () => <div> | ||
<div>some phone number</div> | ||
<div>some email</div> | ||
</div> | ||
|
||
<Contacts /> | ||
``` | ||
|
||
It does not look much in one single instance. But multiply it by more than 500 lists that we have, and each list has a couple of JSX constants and the value shows itself. | ||
|
||
For example, look at this `/SomePath/Product/List.jsx` file: | ||
|
||
``` | ||
const headers = <> | ||
<th>Name</th> | ||
<th>Price</th> | ||
</> | ||
|
||
const row = product => <> | ||
<td>{product.name}</td> | ||
<td>{product.price}</td> | ||
</> | ||
|
||
const listActions = <> | ||
<Categories /> | ||
<Tags /> | ||
<Attributes /> | ||
<Export /> | ||
</> | ||
|
||
const entityActiions = <> | ||
<Images /> | ||
<Categories /> | ||
<Tags /> | ||
<Price /> | ||
</> | ||
|
||
const Products = <List | ||
title='Products' | ||
entityType='Product' | ||
headers={headers} | ||
row={row} | ||
listActions={listActions} | ||
entityActions={entityActions} | ||
/> | ||
|
||
export default Products | ||
``` | ||
|
||
Rendering a JSX fragment inside a file/component is not hard. You render it like `{jsxFragment}`. But when it comes to big systems where you split the system into parts, and develop part separately and reuse parts, that's when it becomes hard. | ||
|
||
# Detailed design | ||
|
||
I recommend that we start with a build configuration flag. In CRA (WebPack) or Vite or any other build system we can configure React to treat JSX framgnets/constants as components: | ||
|
||
``` | ||
{ | ||
treatJsxAsComponent: true | ||
} | ||
``` | ||
|
||
Then we should be able to capitalize the first letter of the JSX constant/variable and render it like a normal component: | ||
|
||
``` | ||
const LightComponent = <div>Light component without props and state</div> | ||
|
||
<LightComponent /> | ||
``` | ||
|
||
The point is that light components won't accept props (they can ignore them with a warning in the console) and they won't have states. | ||
|
||
``` | ||
<LightComponent someKey="someValue" /> | ||
// creates a warning in the console that light components won't support props and those props will be ignored | ||
``` | ||
|
||
# Drawbacks | ||
|
||
Why should we *not* do this? Please consider: | ||
|
||
Since we can create this behavior as a progressive configurational behavior, I can think of no drawback. Any team who wants light components can turn on a flag and get a new behavior. Otherwise, React is just like how it was before. | ||
|
||
# Alternatives | ||
|
||
There are a couple of alternatives. One is to use something like a higher-order component to get the JSX constant, and render it. | ||
|
||
``` | ||
const Contacts = <div>Some contact data here</div> | ||
|
||
const JsxRenderer = ({ jsx }) => { | ||
return <div> | ||
{jsx} | ||
</div> | ||
} | ||
|
||
<JsxRenderer jsx={Contacts} /> | ||
``` | ||
Comment on lines
+118
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the point of You can just write this and skip this useless boilerplate const Contacts = <div>Some contact data here</div>
{Contacts} |
||
|
||
But that adds to the boilerplate even more. It defies the first goal which is to reduce the boilerplate. | ||
|
||
# Adoption strategy | ||
|
||
This feature won't be a breaking change. At first, it can be enabled via a flag. That way no team would be affected by it. | ||
It can stay as a flag for the rest of the React lifecycle. | ||
However, if it become a permanent behavior, then no team should be affected. Because both `<LightComponent />` and `{LightComponent}` should be OK and work. | ||
|
||
# How we teach this | ||
|
||
A new section should be created in the docs called `Light components`. It should explain some limitations for these types of components. | ||
It should also present some examples on when are they useful. And example could be a `<SalesBadge />` simple JSX that can be created in one place and be reused across an online shop without any change. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just do this instead?
I really don't see the point of introducing this new concept. Instead of light components, you can simply use constant JSX elements.