Saltar al contenido principal
Versión: 0.82
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Invocación de funciones nativas en tu componente nativo

En la guía base para crear un nuevo componente nativo, exploraste cómo crear un componente, pasar propiedades del lado JS al nativo y emitir eventos del lado nativo a JS.

Los componentes personalizados también pueden llamar funciones implementadas en el código nativo de forma imperativa, para lograr funcionalidades más avanzadas como recargar una página web programáticamente.

En esta guía aprenderás cómo lograrlo usando un nuevo concepto: Comandos Nativos.

Esta guía parte de la guía de Componentes Nativos y asume que estás familiarizado con ella y con Codegen.

1. Actualizar las especificaciones del componente

El primer paso es actualizar las especificaciones del componente para declarar el NativeCommand.

Update the WebViewNativeComponent.ts as it follows:

Demo/specs/WebViewNativeComponent.ts
import type {HostComponent, ViewProps} from 'react-native';
import type {BubblingEventHandler} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
+import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';

type WebViewScriptLoadedEvent = {
result: 'success' | 'error';
};

export interface NativeProps extends ViewProps {
sourceURL?: string;
onScriptLoaded?: BubblingEventHandler<WebViewScriptLoadedEvent> | null;
}

+interface NativeCommands {
+ reload: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
+}

+export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
+ supportedCommands: ['reload'],
+});

export default codegenNativeComponent<NativeProps>(
'CustomWebView',
) as HostComponent<NativeProps>;

Estos cambios requieren que:

  1. Importes la función codegenNativeCommands de react-native. Esto indica a Codegen que debe generar el código para NativeCommands.

  2. Definas una interfaz que contenga los métodos que queremos invocar en nativo. Todos los Comandos Nativos deben tener un primer parámetro de tipo React.ElementRef.

  3. Exportes la variable Commands, que es el resultado de invocar codegenNativeCommands, pasando una lista de los comandos soportados.

advertencia

En TypeScript, React.ElementRef está obsoleto. El tipo correcto es React.ComponentRef. Sin embargo, debido a un error en Codegen, usar ComponentRef hará que la aplicación falle. Ya tenemos la solución, pero necesitamos lanzar una nueva versión de React Native para aplicarla.

2. Actualizar el código de la aplicación para usar el nuevo comando

Ahora puedes usar el comando en la aplicación.

Open the App.tsx file and modify it as it follows:

App.tsx
import React from 'react';
-import {Alert, StyleSheet, View} from 'react-native';
-import WebView from '../specs/WebViewNativeComponent';
+import {Alert, StyleSheet, Pressable, Text, View} from 'react-native';
+import WebView, {Commands} from '../specs/WebViewNativeComponent';

function App(): React.JSX.Element {
+ const webViewRef = React.useRef<React.ElementRef<typeof View> | null>(null);
+
+ const refresh = () => {
+ if (webViewRef.current) {
+ Commands.reload(webViewRef.current);
+ }
+ };

return (
<View style={styles.container}>
<WebView
+ ref={webViewRef}
sourceURL="https://react.dev/"
style={styles.webview}
onScriptLoaded={() => {
Alert.alert('Page Loaded');
}}
/>
+ <View style={styles.tabbar}>
+ <Pressable onPress={refresh} style={styles.button}>
+ {({pressed}) => (
+ !pressed ? <Text style={styles.buttonText}>Refresh</Text> : <Text style={styles.buttonTextPressed}>Refresh</Text>) }
+ </Pressable>
+ </View>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
alignContent: 'center',
},
webview: {
width: '100%',
- height: '100%',
+ height: '90%',
},
+ tabbar: {
+ flex: 1,
+ backgroundColor: 'gray',
+ width: '100%',
+ alignItems: 'center',
+ alignContent: 'center',
+ },
+ button: {
+ margin: 10,
+ },
+ buttonText: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ color: '#00D6FF',
+ width: '100%',
+ },
+ buttonTextPressed: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ color: '#00D6FF77',
+ width: '100%',
+ },
});

export default App;

Los cambios relevantes son:

  1. Importa la constante Commands del archivo de especificaciones. El comando es un objeto que nos permite llamar a los métodos que tenemos en nativo.

  2. Declara una referencia al componente nativo personalizado WebView usando useRef. Necesitas pasar esta referencia al comando nativo.

  3. Implementa la función refresh. Esta función verifica que la referencia a WebView no sea nula y, si no lo es, llama al comando.

  4. Agrega un componente Pressable para llamar al comando cuando el usuario presione el botón.

Los cambios restantes son ajustes habituales de React para añadir el Pressable y estilizar la vista para que luzca mejor.

3. Volver a ejecutar Codegen

Ahora que las especificaciones están actualizadas y el código está listo para usar el comando, es momento de implementar el código nativo. Sin embargo, antes de escribir código nativo, debes volver a ejecutar Codegen para que genere los nuevos tipos necesarios.

Codegen is executed through the generateCodegenArtifactsFromSchema Gradle task:

bash
cd android
./gradlew generateCodegenArtifactsFromSchema

BUILD SUCCESSFUL in 837ms
14 actionable tasks: 3 executed, 11 up-to-date

This is automatically run when you build your Android application.

4. Implementar el código nativo

Ahora es momento de implementar los cambios nativos que permitirán que tu JS invoque métodos directamente en tu vista nativa.

To let your view respond to the Native Command, you only have to modify the ReactWebViewManager.

If you try to build right now, the build will fail, because the current ReactWebViewManager does not implement the new reload method. To fix the build error, let's modify the ReactWebViewManager to implement it.

ReactWebViewManager.java

//...
@ReactProp(name = "sourceUrl")
@Override
public void setSourceURL(ReactWebView view, String sourceURL) {
if (sourceURL == null) {
view.emitOnScriptLoaded(ReactWebView.OnScriptLoadedEventResult.error);
return;
}
view.loadUrl(sourceURL, new HashMap<>());
}

+ @Override
+ public void reload(ReactWebView view) {
+ view.reload();
+ }

public static final String REACT_CLASS = "CustomWebView";
//...

In this case, it's enough to call directly the view.reload() method because our ReactWebView inherits from the Android's WebView and it has a reload method directly available. If you are implementing a custom function, that is not available in your custom view, you might also have to implement the required method in the Android's View that is managed by the React Native's ViewManager.

5. Ejecutar tu aplicación

Finalmente, puedes ejecutar tu aplicación con los comandos habituales. Una vez que la aplicación esté en funcionamiento, puedes presionar el botón de recarga para ver cómo se vuelve a cargar la página.

Android
iOS