Do nativo para o JavaScript e vice-versa (ou acione componentes nativos no React Native)

Maksym Rusynyk Blocked Desbloquear Seguir Seguindo 28 de novembro de 2018

Se você estiver procurando uma forma de conectar componentes nativos ao JavaScript no React Native, poderá verificar o artigo Como criar pontes nativas de reação e obter PDF Viewer, o que pode ser suficiente na maioria dos casos. Mas e se você precisar atravessar a ponte de outra maneira?

É claro que você pode usar a maneira declarativa e alterar a propriedade, mas não é isso que estamos procurando e não queremos renderizar novamente os componentes reagentes. Além disso, limita o aplicativo com a falta de funcionalidade e dificulta a implementação da funcionalidade, como reload o documento se ele não conseguir carregar ( pode haver alguns problemas de rede ou você precisa atualizar o documento etc. ) ou outras ações como save , refresh , etc. E podemos realmente compará-lo cruzando a ponte de uma maneira só porque não há caminho de volta.

Espero que Reagir Nativo seja poderoso o suficiente e permite chamar componentes nativos do JavaScript também.

Supondo que você já tenha um projeto e um componente que você conectou ao JavaScript, vamos permitir chamar componentes nativos do JavaScript e estender a funcionalidade da ponte .

Isso pode ser feito da seguinte maneira:

  • Implemente a mudança do Android
  • Implemente a mudança e o teste do JavaScript
  • Implemente a alteração do iOS

Abra o gerenciador de vista e implementar getCommandsMap e receiveCommand métodos:

  • getCommandsMap – Deve retornar o mapa entre os nomes dos comandos e IDs que são usados no método receiveCommand
  • receiveCommand – Um método que recebe eventos / comandos diretamente do JavaScript

A implementação será a seguinte:

 private static final int COMMAND_RELOAD = 1; 
 // the code of your view manager 
...
 @Override 
public Map<String,Integer> getCommandsMap() {
return MapBuilder.of("reload", COMMAND_RELOAD);
}
 public void receiveCommand(final PDFView view, int command, final ReadableArray args) { 
switch (command) {
case COMMAND_RELOAD: {
// The code you are going to execute when the command is called
break;
}
default: {
break;
}
}
}

E como podemos ver, é muito simples de implementar e você pode facilmente estendê-lo com outros comandos também.

A implementação requer Manipulação Direta e acesso ao componente ( pode ser acessado usando ref ):

 <RNPDFView 
ref={ref => {
this._viewerRef = ref;
}}
{/* other attributes */}
/>

O próximo passo é definir a função de reload que acionará o comando e é um pouco diferente para Android e iOS:

  • No Android, podemos usar o UIManager e o dispatchViewManagerCommand ;
  • No iOS, acessamos o gerenciador de visualização e chamamos seu método para acionar o evento.

A implementação será:

 // Imports and other code 
 class PDFView extends React.Component<Props, *> { 
// component implementation

reload() {
if (this._viewerRef) {
const handle = findNodeHandle(this._viewerRef);
 if (!handle) { 
throw new Error('Cannot find node handles');
}
 await Platform.select({ 
android: async () => {
return UIManager.dispatchViewManagerCommand(
handle,
UIManager.PDFView.Commands.reload,
[],
);
},
ios: async () => {
return NativeModules.PDFViewManager.reload(handle);
},
})();
} else {
throw new Error('No ref to PDFView component, check that component is mounted');
}
}
}

E em seu aplicativo, depois ref ao PDFView componente é recebido, acionar a reload comando:

 // Event that can be triggered by some button 
onButtonClick = () => {
this.reload();
}
 // A method that triggers reload 
reload = () => {
if (this._pdfRef) {
this._pdfRef.reload();
}
}
 // Get ref to component 
onRef = (ref: ?PDFView) => {
this._pdfRef = ref;
}
 render() { 
// other code
return (
{/* App implementation */}
<PDFView
{/* Other properties */}
onRef={this.onRef}
/>
);
}

Isso é tudo. Agora o método de reload pode ser chamado de qualquer lugar do aplicativo e sempre que for necessário. Não há necessidade de forçar propriedades a alterar ou recarregar componentes reagentes.

Agora, quando a ponte JavaScript para Android estiver pronta e funcionando, é hora de implementá-la no iOS. A implementação para iOS é um pouco diferente e exige do componente que exponha o método que deve ser acionado. RCT_EXPORT_METHOD é usado para isso:

 RCT_EXPORT_METHOD(reload: (nonnull NSNumber *)reactTag resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) { 
// implementation
}

e o método exportado fornece parâmetros e promessas de reactTag . Usando uiManager e recebeu reactTag é possível obter a instância do espectador:

 PDFView *view = (PDFView *)[self.bridge.uiManager viewForReactTag: reactTag]; 

..e depois disso, qualquer método do visualizador pode ser acionado ( recarregar no caso atual ). A implementação final será:

 RCT_EXPORT_METHOD(reload: (nonnull NSNumber *)reactTag resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) { 
dispatch_async(dispatch_get_main_queue(), ^{
PDFView *pdfView = (PDFView *)[self.bridge.uiManager viewForReactTag: reactTag];
if (!pdfView) {
reject(ERROR_INVALID_REACT_TAG, [NSString stringWithFormat: @"ReactTag passed: %@", reactTag], nil);
return;
}
[pdfView reload];
resolve(nil);
});
}

Não é muito trabalhoso colmatar algo de JavaScript para nativo e para trás, e ter essas pontes nos permite estender significativamente a funcionalidade do React Native – e, por exemplo, melhorar o desempenho de algumas partes críticas do aplicativo que exigem melhor desempenho, implementar funcionalidade ausente ou reutilizar alguns dos componentes que já foram desenvolvidos. Além disso, isso prova mais uma vez que as possibilidades do React Native são realmente incríveis e o React Native permite desenvolver aplicativos maduros com menos esforço para ambas as plataformas – iOS e Android.

Todas as técnicas descritas são usadas no Visualizador de PDF para reagir ao componente nativo que também inclui um projeto de demonstração onde você pode verificar como a ponte funciona, etc.

Texto original em inglês.