react-native
react-native copied to clipboard
Add support for blur and focus on View
Summary:
As the title suggests: adds support strictly to View components on Android for onFocus and onBlur events. This is especially helpful for apps that respond to controller or remote inputs and aligns with existing support for the focusable prop.
In order to make this change cross-compatible with text inputs, TextInputFocusEvent has been deprecated in favor of the BlurEvent/FocusEvent types now available from core. Their type signatures are identical but BlurEvent/FocusEvent should be the type going forward for all views that intend to support focus/blur. Text inputs intentionally do not forward information about their state upon focus/blur and docs specifically call out onEndEditing as a means of reading state synchronously when blurring. Therefore, the changes to the native side to remove the event type specifically for text inputs is not breaking.
Changelog: [Android][Added] - Support for onFocus and onBlur function calls in View components
Differential Revision: D75238291
This pull request was exported from Phabricator. Differential Revision: D75238291
This pull request was exported from Phabricator. Differential Revision: D75238291
cc @douglowder since there's some overlap with TV. However, this change only adds support for Android at the moment, and only targets the View component rather than others like Image. I'm keeping this change as minimal as possible, not baking it into the BaseViewManager because not all components emit focus and blur events.
I also haven't fully settled onto an appropriate solution for iOS, but I'd like there to be true support for focusable/keyboard navigation on there first.
This pull request was exported from Phabricator. Differential Revision: D75238291
This pull request was exported from Phabricator. Differential Revision: D75238291
This pull request has been merged in facebook/react-native@af0a76cf5fdb8107294dff2c9aa0dbc36c7d5443.
This pull request was successfully merged by @Abbondanzo in af0a76cf5fdb8107294dff2c9aa0dbc36c7d5443
When will my fix make it into a release? | How to file a pick request?
Hi @Abbondanzo , I found this PR after facing some type issues with FocusEvent and BlurEvent by updating Expo SDK from 53 to 54.
Before the update, both onFocus and onBlur emitted NativeSyntheticEvent<TextInputFocusEventData>. Now they emit FocusEvent and BlurEvent.
And they look like this:
https://github.com/facebook/react-native/blob/36e1c0afed7a3e845d424e6ab89aa8ecbaf74bc6/packages/react-native/Libraries/Types/CoreEventTypes.d.ts#L247-L253
While before, TextInputFocusEventData contained little more info than TargetedEvent:
https://github.com/facebook/react-native/blob/36e1c0afed7a3e845d424e6ab89aa8ecbaf74bc6/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts#L462-L465
And I printed event.nativeEvent in the console, it still contains eventCount and text:
I'm accessing text of TextInput on both focus & blur. And I wonder if you removed it for any specific purpose?
If not, then I believe it should be updated to:
export interface TargetedEvent {
target: number;
}
export interface TextInputEvent extends TargetedEvent {
text: string;
eventCount: number;
}
export type BlurEvent = NativeSyntheticEvent<TextInputEvent>;
export type FocusEvent = NativeSyntheticEvent<TextInputEvent>;
Let me know what you think!
Hi @thisisgit, would love to learn more about your use cases. The BlurEvent and FocusEvent types were intentionally made more abstract because all views now support focus and blurring events, not just text inputs. Since there is an existing event onEndEditing that emits the text input's state identically to that of the old blur event, that event is the recommendation if you are attempting to access text state. As the documentation for onBlur states:
If you are attempting to access the text value from nativeEvent keep in mind that the resulting value you get can be undefined which can cause unintended errors. If you are trying to find the last value of TextInput, you can use the onEndEditing event, which is fired upon completion of editing.
We haven't fully removed the text value from event payloads on iOS yet but it shouldn't be relied upon. Android does not emit this value from either onFocus or onBlur.
@Abbondanzo Thanks for the quick reply. I didn't know text value isn't present on Android! I'm currently only working on iOS and wasn't aware of that.
So I was referring to that text field since I needed to store the text to wipTextRef and refer to it when focused TextInput unmounts:
useEffect(() => {
return () => {
if (!isFocusedRef.current) return;
if (wipTextRef.current && wipTextRef.current.length > 0) {
// Update
} else {
// Delete
}
};
}, []);
And setting wipTextRef happens onFocus & onChangeText.
onFocus because it needs to be initialized to handle case where user focuses the input but transition the screen without changing the text. And I was assigning the variable with the payload's text.
But if text value of the payload isn't reliable, then I guess I should use the variable that is being passed to defaultValue prop of the TextInput in onFocus event. I guess it's safe to use that variable for my case as I sync it with the text in TextInput every time it goes on blur.
It could go wrong if the sync on blur don't work for some reason, but I think it's the only possible way without using value prop TextInput to be able to access up-to-date text on focus event. AFAIK there's no imperative way to retrieve text of TextInput as well so I guess if the current approach doesn't work, then I would have no choice but to make it controlled TextInput.
And thanks for sharing alternative of onBlur. It works perfectly