-
Notifications
You must be signed in to change notification settings - Fork 47.4k
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
Support Symbol keys for props #7552
Comments
Can you please explain your use case for this? |
Framework-specific props For example, brabadu/tanok (internal implementation of elm-architecture) uses convention with I guess, Isn't a possibility of receiving
? |
A framework could also choose a cryptographically random 64-character alphanumeric key, which would effectively eliminate any possibility of a name conflict. Save it to a variable and use it as a symbol, if so desired. Another workaround is to create a prop called The simplicity of "keys are strings" is something that I'm a little reluctant to give up. If component authors start accepting symbols as keys, things become more complicated. For instance, what is the story around JSX? My intuition is that if we do anything, perhaps it should be to throw a warning if we encounter a symbol as a prop key. |
Random string key is a fine alternative, but it has the same "overloaded" look in JSX as a symbol does: import { randomKey } from 'framework'
<Component {...{[randomKey]: 'lol'}} /> |
Replaced passing |
I'd like to argue in favor of @zemlanin's use case. The very purpose of I think the more useful simplifying guideline would be "react prop keys are just like object prop keys" (rather than just "keys are strings"). For the most part they are exactly object keys, and when dealing with JSX you can use the spread operator the same way you do with objects. There is no slippery slope towards supporting all manner of exotic types as prop keys, any more than there is for object keys. The valid key types are simply: React has tried to stick close to ES6+ in terms of style so far, it would be nice to continue along those lines by treating Symbols the same way ES6 does - i.e. collision-proof private key identifiers, for use by frameworks and extension mechanisms, never iterated over, but usually copied (e.g. by In terms of JSX syntax implications, again, I don't see anything special that would need to be done here. Props are always strings, so you wouldn't be able to use symbols there, it would either have to be as part of the spread object, or with Random prop names or long namespaced names like |
Another use case: const namespace = (ns, ...hocs) => compose(
withProps(props => ({ $parentProps: props })), // TODO $parentProps as symbol
...hocs,
mapProps(props => ({ [ns]: props, ...props.$parentProps }))
) |
Yet another use case. https://reacttraining.com/react-router/web/guides/dealing-with-update-blocking <UpdateBlocker location={location}>
<NavLink to='/about'>About</NavLink>
<NavLink to='/faq'>F.A.Q.</NavLink>
</UpdateBlocker> In react-router v4, the suggested practice for ensuring that pure components have their impure react-router children update is to pass an otherwise unused const props = {
...
[Symbol('location')]: location
};
<UpdateBlocker {...props}>
<NavLink to='/about'>About</NavLink>
<NavLink to='/faq'>F.A.Q.</NavLink>
</UpdateBlocker> This was one of those things that I tried, only to be mildly surprised that it didn't work. (In my case the syntax was cleaner than above, because the prop was being injected via react-redux
...completely nails it, in my opinion. |
Another use case is to create non-enumerable props. Take, for instance, a component that is wrapped in a container that injects additional props in ( A common React convention is to use the spread operator to select specific props and pass the rest down, like so: render() {
const { backgroundColor, ...restProps } = this.props
return (
<div style={{ backgroundColor }}>
<ChildComponent {...restProps} />
</div>
)
} This would inadvertently pass And it would certainly be much more natural to use |
It sounds to me like this is just trying to work around the real problem (HOC pattern pollutes props) with a solution that further obscures it. We are looking at revamping the context API in a way that doesn’t present this problem. Would this help you? |
Ah, yeah, this is cool. I didn't want to use context because the current API didn't really seem much better than props, since it still deals with naming collisions and such. Nice proposal! 👍 |
It's a lovely proposal (I am 👍 for the proposal itself), but not all uses of Symbol props translate to using contexts instead. Sometimes you want the locality actual props provide. Most use cases here have something to do with components that are intentionally coupled with each-other and meant to be used together as a coherent set. Sometimes this works best with contexts (e.g. forms and their fields) but other times, the communication really has to happen between parent and direct children only. E.g. the way |
We have some very rough ideas about solving these use cases too without the notion of private props. |
Oh heck yeah, that would be much better. Between the context proposal and the |
The call return API previously mentioned was never finalised and has since been removed. There are times where library authors may want to attach pass private values through levels of consumer components via props. Is there any serious reason not to support Symbols in props? |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution. |
Is there any info available on why call return was scrapped? |
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any additional information, please include with in your comment! |
bump |
One issue I am having is the Context API doesn't seem to have a way to know the order of components. So that leads to using a parent child set of components where the parent has to tell the child its index via cloning children. |
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! |
bumpity bump |
Just ran into this today, was a bit surprising that it just got silently stripped 🤔 My use case was to pass internal props down to specific children, in this case the background color to the import React, { ReactElement } from 'react'
import { View } from 'react-native'
import { HStack, VStack } from 'react-stacked'
const kBackgroundColor = Symbol('BackgroundColor')
interface CellProps {}
export const Cell: React.FC<CellProps> = ({ children }) => (
<View style={{ flexBasis: 1, flexGrow: 1, flexShrink: 0 }}>{children}</View>
)
interface RowProps {
[kBackgroundColor]?: string
children?: ReadonlyArray<ReactElement<CellProps>> | ReactElement<CellProps> | null
}
export const Row: React.FC<RowProps> = ({ children, ...props }) => (
<HStack backgroundColor={props[kBackgroundColor]}>{children}</HStack>
)
interface TableProps {
children?: ReadonlyArray<ReactElement<RowProps>> | ReactElement<RowProps> | null
}
export const Table: React.FC<TableProps> = ({ children }) => (
<VStack>
{React.Children.map(children, (child, index) => (
React.cloneElement(child, { [kBackgroundColor]: ['#fff', '#eee'][index % 2] })
))}
</VStack>
) I guess I could create a context for each row, but my gut feeling is that performance will suffer 😅 edit: My primary use case for this is that I don't want my internal props to show up in autocompletion, and I'm using TypeScript. With those two prerequisites I found this workaround that I think is acceptable: const kBackgroundColor: unique symbol = '_backgroundColor' as any This will treat |
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! |
bümp |
I don't think we should support this. The purpose of props is to be explicit about which data gets passed down. If you want to make it more implicit and "secret" between two components, you can use Context. Patterns that rely on |
Do you want to request a feature or report a bug?
I want to report a bug
What is the current behavior?
render()
doesn't receive props with Symbol keys (for example,{[Symbol()]: 'lol'}
). I guess it is because ofhasOwnProperty
in ReactElement.createElementIf the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via jsfiddle or similar.
https://jsfiddle.net/sh2xbm3x/1/
What is the expected behavior?
Symbol-keyed
props
passed torender()
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Every single one, as far as I know
The text was updated successfully, but these errors were encountered: