将屏幕定义的函数传递到标题时触发“非可序列化”问题。

huangapple go评论89阅读模式
英文:

Passing screen-defined function to header triggering "Non-serializable" issue

问题

我在一个堆栈导航器中有一个屏幕,在其中我已经定义了全局标题栏,包含一个按钮,该按钮将触发一个模态框。我遇到的问题是,我正在在屏幕组件内部定义触发模态框的函数,并尝试通过navigation.setParams传递函数,但我遇到了警告:

> 在导航状态中找到了不可序列化的值

const ViewB = ({ route, navigation }) => {
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    navigation.setParams({showModal: () => setShowModal(true)});
  }, []);
<Stack.Screen name="ViewB" component={ViewB} options={({ route }) => ({
  headerRight: () => (
      <View>
          <Button onPress={() => {
              showModal = route?.params?.["showModal"];
              showModal && showModal();
          }} title="Toggle modal" />
      </View>
  )
})} />

在Google搜索之后,我找到了官方文档上关于这个问题的信息,还有这个 SO 问题/答案解释了RN不喜欢我们将函数传递给navigation,因为如果事情发生变化等等,它可能会破坏功能... 但是我不确定有没有更好的方法来解决这个问题。

有没有一种方法可以在不引起React Native不适的情况下实现我期望的结果?

这是一个包含我的示例的堆栈

英文:

I have a stack navigator in which one of my screens, I have defined the global header bar to contain a button that will trigger a modal. The issue I have is that I am defining the function to trigger said modal from within the screen component itself and attempting to pass the function via navigation.setParams and I am facing the warning:

> Non-serializable values were found in the navigation state

const ViewB = ({ route, navigation }) => {
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    navigation.setParams({showModal: () => setShowModal(true)});
  }, []);
<Stack.Screen name="ViewB" component={ViewB} options={({ route }) => ({
  headerRight: () => (
      <View>
          <Button onPress={() => {
              showModal = route?.params?.["showModal"];
              showModal && showModal();
          }} title="Toggle modal" />
      </View>
  )
})} />

After Googling I did come across the official docs on the issue and also this SO question/answer that explained that RN doesn't like us passing functions to navigation as it could potentially break functionality down the line if things change etc... however I'm unsure of a better way to go about this.

Is there a way in which I can achieve my desired result without upsetting react-native?

Here is a stack with my example

答案1

得分: 1

是的,react-navigation 不允许我们将方法传递给导航 props。

根据您的要求,无需将方法传递给父级参数。

您可以通过在屏幕代码中添加 headerRight 来实现这一点,请查看以下代码更好地理解。

const ViewB = ({ route, navigation }) => {
  const [showModal, setShowModal] = useState(false);

  useLayoutEffect(() => {
    navigation.setOptions({
      headerRight: () => (
        <View>
          <Button
            onPress={() => {
              setShowModal(true);
            }}
            title="Toggle modal"
          />
        </View>
      ),
    });
  }, [navigation]);

  const onBackPress = () => {
    navigation.navigate(route.params.previousScreen, {
      val: 5,
      val2: 6,
    });
  };

  return (
    <View>
      <Text>ViewB</Text>
      <Text>Params: {JSON.stringify(route.params)}</Text>
      <Button title="back" onPress={onBackPress} />
      {showModal && <Modal onClose={() => setShowModal(false)} />}
    </View>
  );
};

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator mode="modal">
        <Stack.Screen name="ViewA" component={ViewA} />
        <Stack.Screen name="ViewB" component={ViewB} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

请注意,我只翻译了代码部分,没有包括其他内容。

英文:

Yes, react-navigation doesn't allow us to pass the methods in navigation props.

As per your requirement there is no need to pass the method in the params to the parent.

you can achieve this by adding the headerRight inside your screen code, checkout the below code changes for better understanding.

const ViewB = ({route, navigation}) =&gt; {
  const [showModal, setShowModal] = useState(false);

  useLayoutEffect(() =&gt; {
    navigation.setOptions({
      headerRight: () =&gt; (
        &lt;View&gt;
          &lt;Button
            onPress={() =&gt; {
              setShowModal(true);
            }}
            title=&quot;Toggle modal&quot;
          /&gt;
        &lt;/View&gt;
      ),
    });
  }, [navigation]);

  const onBackPress = () =&gt; {
    navigation.navigate(route.params.previousScreen, {
      val: 5,
      val2: 6,
    });
  };

  return (
    &lt;View&gt;
      &lt;Text&gt;ViewB&lt;/Text&gt;
      &lt;Text&gt;Params: {JSON.stringify(route.params)}&lt;/Text&gt;
      &lt;Button title=&quot;back&quot; onPress={onBackPress} /&gt;
      {showModal &amp;&amp; &lt;Modal onClose={() =&gt; setShowModal(false)} /&gt;}
    &lt;/View&gt;
  );
};

export default function App() {
  return (
    &lt;NavigationContainer&gt;
      &lt;Stack.Navigator mode=&quot;modal&quot;&gt;
        &lt;Stack.Screen name=&quot;ViewA&quot; component={ViewA} /&gt;
        &lt;Stack.Screen name=&quot;ViewB&quot; component={ViewB} /&gt;
      &lt;/Stack.Navigator&gt;
    &lt;/NavigationContainer&gt;
  );
}

huangapple
  • 本文由 发表于 2023年7月31日 18:45:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76802867.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定