First proposal of the reflection in React
Hi guys,
I have added a proposal for reflection in React. Please let me know if I've done it correctly or not.
Thank you so much.
Hi @Nefcanto!
Thank you for your pull request and welcome to our community.
Action Required
In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.
Process
In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.
Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.
If you have received this in error or have any questions, please contact us at [email protected]. Thanks!
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!
Wondering which particular helpers you have in mind, because the ones listed in the RFC are covered by native js functionality (Array.isArray) or react-is
@theKashey, thank you for the link. I did not know about react-is. But as I looked at it and the name suggests, it's only about checking a fact about a given thing.
Let me give a list of ideas I have in mind for react-reflection:
- Retrieving information about the app itself => something like
getComponents - Finding a specific component =>
getComponent("ComponentName") - Get information about props =>
getProps(component) - Get one specific prop =>
getProp(component, "PropName") - Check for the presence of a prop =>
hasProp(component, "PropName") - Get the list of hooks used in the component =>
getHooks(component) - Get the list of states used in the component =>
getStates(component) - Get the list of dependencies for a given hook =>
getDependencies(hook)orgetDependencies(component, "HookName") - Getting the type of an object (not checking if it is something) =>
getType(object)=> These could be: Fragment, Array, FunctionComponent, ClassComponent, Hook, State, etc. - Creating a dynamic instance of a component if possible, without being in DOM =>
createInstance(component)
The list can go on. We do use all of these reflection ideas in C#.
I might be missing something.
From my perspective reflection in programming language is mostly there because the programmer "lost" some information. Sometimes this is by accident, in other cases this is because there is a "dynamic" situation where the writer of the code does not know all the details of how it is being used.
In my experience, when using a form of reflection, most of the time the complexity is introduced where it could have been prevented at another point in the program. A simple example:
Let's say I am receiving an array with mixed types, something like
[true, 1, { banana: 'yellow' }]. If I need to process this information I might need to do a check fortypeof. I could have prevented this by supplying different data:[{ type: 'boolean', value: true }, { type: 'number', value: 1 }, { type: 'object', value: { banana: 'yellow' } }].
So in most cases I try to resolve the need for reflection by making code more explicit. For me reflection is a red flag that signals accidental complexity in my application.
What is the use case you need reflection for?
@EECOLOR, your example is true. We can add more data to the leaf nodes. The more data we feed, the less data we need to extract dynamically.
But this approach has many downsides:
- It works as long as the leaf components are under your control. You won't be able to do this if you do not have access to the code you want to use. Third-party components won't be covered.
- It increases boilerplate code in leaf components by the multitude. Let's say you have 500 lists in an application. And you want to send each list a bunch of actions. One list might have a simple "icon + text" action. Another list might need an array of iconic actions. Which one makes more sense? Providing the metadata in 500 places? Or extracting the metadata in one place? This is one example of the requirements we do have. Consider this list:
const Customers = () => {
return <List
title="Customers"
listActions={<ListAction
title="CalculateBalances"
iconic
/>}
/>
}
And compare it to:
const Customers = () => {
return <List
title="Customers"
listActions={<ListAction
title="CalculateBalances"
iconic
/>}
listActionsType="singleComponent"
listActionsPresentation="iconic"
/>
}
The first component reduces the boilerplate code. That counts as the system grows.
- Providing metadata sometimes becomes extremely tricky. Extracting metadata is a better approach for some use cases. Consider these lists:
const Customers = () => {
return <List
title="Customers"
listActions={<ListAction
title="CalculateBalances"
iconic
/>}
/>
}
const Users = () => {
return <List
title="Users"
listActions={<>
<ListAction title="SendNotification" />
<ListAction title="AnalyzeForVulnerabilities" />
</>}
/>
}
const Orders = () => {
return <List
title="Orders"
listActions={<>
<ListAction title="CalculateTotals" />
<ListActionMenu>
<ListAction title="MakeSpreadsheet" />
<ListAction
title="ApplyDiscount"
admin
/>
</ListActionMenu>
</>}
/>
}
What metadata can we provide to signal to the List component that the list actions have a menu in it, and one item of that menu should only be shown for admin users?
The point is, while your example is true, there are some use cases when providing more metadata to the system is not a better approach, and extracting data from the system makes more sense.
I didn't want to close this. I just wanted to clean the clutter on my account. I didn't know that deleting a fork causes this to be closed. This feature is still very much needed indeed.
I'm opening this, as we do need this feature for our complex SPL.