如何在 React Native 中重新设置组件的父级?

How to reparent a component in ReactNative?

在下面的代码中,我希望 webView 的内容不会随着点击次数的增加而改变,但每次加载时,都会显示一个新的时间戳。

const webView = (
  <WebView
    source={{
      uri:
        'data:text/html,<html><script>document.write("<h1 style=\"font-size:64px\">"+Date.now()+"<h1>");</script>',
    }}
  />
);


export default class App extends React.Component {
  state = {
    clicks: 0,
  };

  onClick = () => {
    this.setState({ clicks: this.state.clicks + 1 });
  };

  render() {
    return (
      <View>
        <Text onPress={this.onClick}>
          Click Me: {this.state.clicks}
        </Text>

        {this.state.clicks % 2 === 0 ? webView : null}
        {this.state.clicks % 2 === 1 ? webView : null}
      </View>
    );
  }
}

Link 到 expo snack 在设备上检查它。

到目前为止,我已经阅读了有关在 React 中重新设置父级的问题 here, implementing using Portals, and also saw an issue 关于支持在 React Native 中重新设置父级但没有解决方案。

那么,如何在多个屏幕中重用一个组件实例,而不是在每个屏幕中都创建一个新实例?

希望重新设置父级是答案,但找不到任何实现,所以如果重新设置是这个问题的答案,我该如何实现?

这里的问题是,在每次状态更改时,您的组件都会重新呈现 webView 对象并显示当前日期。我建议您将 webView 更改为一个组件,并在调用 WebViewComp 时添加一个静态键,以防止每次状态更改时 unmount/mount。

const WebViewComp = () => ( //Change declaration to function component instead of constant object
  <WebView
    source={{
      uri:
        'data:text/html,<html><script>document.write("<h1 style=\"font-size:64px\">"+Date.now()+"<h1>");</script>',
    }}
  />
);

export default class App extends React.Component {
  state = {
    clicks: 0,
  };

  onClick = () => {
    this.setState({ clicks: this.state.clicks + 1 });
  };

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.paragraph} onPress={this.onClick}>
          Click Me: {this.state.clicks}
        </Text>

        {this.state.clicks % 2 === 0 ? <WebViewComp key="child" /> : null}
        {this.state.clicks % 2 === 1 ? <WebViewComp key="child" /> : null}
      </View>
    );
  }
}

您肯定需要重新设置视图的父级。我搜索了一些像 React Portals 一样工作的库。

我们有两个可用的项目:

我测试了第二个包 (rn-native-portals),这对 Android:

产生了神奇的效果

如何安装

  1. npm install mfrachet/rn-native-portals

  2. react-native link(不幸的是我们还不能自动link这个,但是我们可以提交PR)

实施

您的目标元素需要在 <PortalOrigin>

import React from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { PortalOrigin } from 'rn-native-portals';

class Target extends React.Component {
  state = {
    moveView: false,
  }

  render() {
    return (
      <>
        <TouchableOpacity
          style={{ flex: 1 }}
          onPress={() => this.setState({ moveView: !this.state.moveView })}
        >
          <Text>Press Here</Text>
        </TouchableOpacity>

        <PortalOrigin destination={this.state.moveView ? 'destinationPortal' : null}>
          <View>
            <Text>This text will appear on destination magically...</Text>
          </View>
        </PortalOrigin>
      </>
    );
  }
}

export default Target;

在目的地使用这个(不要忘记设置相同的唯一门户名称)

import React from "react";
import { PortalDestination } from "rn-native-portals";

class Destination extends React.Component {
  render() {
    return (
      <PortalDestination name="destinationPortal" />
    );
  }
}

export default Destination;

这个项目很棒,但绝对需要我们社区的帮助来创建更好的文档。

我有一个项目需要使用此功能,将视频重新设置为屏幕外。我正在认真考虑 PR auto-link 支持以避免编译警告。

更多有用信息: