如何用自定义RenderCallback改写Stack Navigator以适应长尾词查询?

2026-04-02 07:251阅读0评论SEO教程
  • 内容介绍
  • 相关推荐

本文共计2448个文字,预计阅读时间需要10分钟。

如何用自定义RenderCallback改写Stack Navigator以适应长尾词查询?

目录 + 使用Stack Navigator和component props传递组件 + 无因素引起组件更新时,使用render callback的效果 + 因素引起组件更新时,使用component props的效果

目录
  • Stack Navigator使用component props传递组件
  • 无因素引起组件更新时,使用render callback的效果
  • 有因素引起组件更新时,使用component props的效果
  • 有因素引起组件更新时,使用render callback的效果
  • 有因素引起组件更新时,在render callback中使用React.memo
  • 有因素引起组件更新时,在render callback中使用useCallback
  • 总结

Stack Navigator使用component props传递组件

通常来说,Stack Navigator的默认用法,是这样的

如何用自定义RenderCallback改写Stack Navigator以适应长尾词查询?

<NavigationContainer>\ <Stack.Navigator>\ <Stack.Screen name="Home" component={HomeScreen} />\ </Stack.Navigator>\ </NavigationContainer>

自定义的组件HomeScreen是作为component属性,传递给Stack.Screen的。这种默认的做法,会让Stack.Screen对Screen Component进行优化,避免了很多不必要的渲染。官方文档中,是这样描述的。

Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you useReact.memoorReact.PureComponentfor your screen components to avoid performance issues.

从这段话中,我们可以看出,当使用自定义的render callback时,避免组件重复渲染的工作,就移交给了使用者。render callback通常是为了传递extra props,但是优化方式和extra props是没什么关系的,以下的例子中,为了避免干扰,没有新引入extra props,只是用stack navigator传递给组件的默认属性来举例子。

为了更好的监控,HomeScreen是否被重复渲染,在代码中打印了一个随机数,便于观察日志输出。

无因素引起组件更新时,使用render callback的效果

下面这段代码,使用了render callback来渲染HomeScreen。

const homeInst = (props) => (<HomeScreen {...props} />)

运行起来的效果和不使用render callback的效果是一样的。在频繁的HomeScreen和DetailsScreen切换过程中,因为没有引起HomeScreen重绘的因素存在,所以HomeScreen并没有被重复渲染。

import React from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To Detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const homeInst = (props) => (<HomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen}/> </Stack.Navigator> </NavigationContainer> ) } export default App

有因素引起组件更新时,使用component props的效果

为了引起HomeScreen组件的更新,以便验证Screen Navigator是否对HomeScreen做了避免重复渲染的优化,在代码中加入了一个新的状态age,当点击Button时,这个age不断的自增1,因为App里有state的更新,所以作为父组件的App会更新,而作为子组件的HomeScreen通常意义上(不通常的情况下,就是使用了React.memo等优化手段)说,也会重新渲染。因为这就是React的重绘机制:从父组件开始,一层一层向下重绘。

import React, {useState} from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home' component={HomeScreen} /> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

当我点击Button后,发现HomeScreen并没有重绘,所以当使用component props传递组件时,Stack Navigator确实是做了防止不必要重绘的优化。

具体效果可以参考下面的动画:

有因素引起组件更新时,使用render callback的效果

那么在上面所说的场景下,用render callback会怎么样呢?答案显而易见,如果没有做任何优化处理,那么HomeScreen的不必要的重复渲染,是无法避免的了。

代码如下:

import React, { useState } from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) const homeInst = (props) => (<HomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

动画效果如下:

可以看到,当我点击Button改变App的状态时,本来没有必要变化的HomeScreen,就疯狂的重绘了起来,当然每次重绘的结果,都和之前一样,这就是无效的重绘,我们应该避免。

有因素引起组件更新时,在render callback中使用React.memo

根据上面官网文档给出的提示,如果想避免重绘,应该用React.memo (因为感觉FB已经全面拥抱Hook了,所以这里也不考虑PureComponent了)来包装你的组件。

const MemoHomeScreen = React.memo(HomeScreen)

说一百句,也顶不上一句代码,具体代码如下(都是可以copy到你的环境中直接运行的):

import React, {useState} from 'react'; import { View, Text, Button } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() const MemoHomeScreen = React.memo(HomeScreen) function App() { const [age, setAge] = useState(20) const homeInst = (props) => (<MemoHomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App;

上面这段代码的运行效果,和使用component props传递HomeScreen的运行效果一样。只不过前者是使用者自己优化了重绘,后者是Stack Navigator替你优化了。

有因素引起组件更新时,在render callback中使用useCallback

如果我们再稍微多想一下,hostInst本质上是一个function,而说道function的避免重复计算的手段,自然想到了useCallback。我用useCallback来包装一下,看看是否能达到一样的效果:

const homeInst = useCallback((props) => (<HomeScreen {...props} />), [])

完整代码如下:

// In App.js in a new project import React, {useState, useCallback} from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) const homeInst = useCallback((props) => (<HomeScreen {...props} />), []) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

我试了一下,效果和使用React.memo是一样的,都可以达到避免无效重复绘制HomeScreen的目的。

总结

Stack Navigator的使用,除非特殊情况,非得加extraData,否则强烈推荐用props的方式传递组件,减少思维负担。如果要使用render callback,那么我是推荐使用useCallback代替React.memo的,因为配合useCallback的第二个参数,控制起来更加有针对性。

以上就是详解Stack Navigator中使用自定义的Render Callback的详细内容,更多关于Stack Navigator自定义Render Callback的资料请关注易盾网络其它相关文章!

本文共计2448个文字,预计阅读时间需要10分钟。

如何用自定义RenderCallback改写Stack Navigator以适应长尾词查询?

目录 + 使用Stack Navigator和component props传递组件 + 无因素引起组件更新时,使用render callback的效果 + 因素引起组件更新时,使用component props的效果

目录
  • Stack Navigator使用component props传递组件
  • 无因素引起组件更新时,使用render callback的效果
  • 有因素引起组件更新时,使用component props的效果
  • 有因素引起组件更新时,使用render callback的效果
  • 有因素引起组件更新时,在render callback中使用React.memo
  • 有因素引起组件更新时,在render callback中使用useCallback
  • 总结

Stack Navigator使用component props传递组件

通常来说,Stack Navigator的默认用法,是这样的

如何用自定义RenderCallback改写Stack Navigator以适应长尾词查询?

<NavigationContainer>\ <Stack.Navigator>\ <Stack.Screen name="Home" component={HomeScreen} />\ </Stack.Navigator>\ </NavigationContainer>

自定义的组件HomeScreen是作为component属性,传递给Stack.Screen的。这种默认的做法,会让Stack.Screen对Screen Component进行优化,避免了很多不必要的渲染。官方文档中,是这样描述的。

Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you useReact.memoorReact.PureComponentfor your screen components to avoid performance issues.

从这段话中,我们可以看出,当使用自定义的render callback时,避免组件重复渲染的工作,就移交给了使用者。render callback通常是为了传递extra props,但是优化方式和extra props是没什么关系的,以下的例子中,为了避免干扰,没有新引入extra props,只是用stack navigator传递给组件的默认属性来举例子。

为了更好的监控,HomeScreen是否被重复渲染,在代码中打印了一个随机数,便于观察日志输出。

无因素引起组件更新时,使用render callback的效果

下面这段代码,使用了render callback来渲染HomeScreen。

const homeInst = (props) => (<HomeScreen {...props} />)

运行起来的效果和不使用render callback的效果是一样的。在频繁的HomeScreen和DetailsScreen切换过程中,因为没有引起HomeScreen重绘的因素存在,所以HomeScreen并没有被重复渲染。

import React from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To Detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const homeInst = (props) => (<HomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen}/> </Stack.Navigator> </NavigationContainer> ) } export default App

有因素引起组件更新时,使用component props的效果

为了引起HomeScreen组件的更新,以便验证Screen Navigator是否对HomeScreen做了避免重复渲染的优化,在代码中加入了一个新的状态age,当点击Button时,这个age不断的自增1,因为App里有state的更新,所以作为父组件的App会更新,而作为子组件的HomeScreen通常意义上(不通常的情况下,就是使用了React.memo等优化手段)说,也会重新渲染。因为这就是React的重绘机制:从父组件开始,一层一层向下重绘。

import React, {useState} from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home' component={HomeScreen} /> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

当我点击Button后,发现HomeScreen并没有重绘,所以当使用component props传递组件时,Stack Navigator确实是做了防止不必要重绘的优化。

具体效果可以参考下面的动画:

有因素引起组件更新时,使用render callback的效果

那么在上面所说的场景下,用render callback会怎么样呢?答案显而易见,如果没有做任何优化处理,那么HomeScreen的不必要的重复渲染,是无法避免的了。

代码如下:

import React, { useState } from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) const homeInst = (props) => (<HomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

动画效果如下:

可以看到,当我点击Button改变App的状态时,本来没有必要变化的HomeScreen,就疯狂的重绘了起来,当然每次重绘的结果,都和之前一样,这就是无效的重绘,我们应该避免。

有因素引起组件更新时,在render callback中使用React.memo

根据上面官网文档给出的提示,如果想避免重绘,应该用React.memo (因为感觉FB已经全面拥抱Hook了,所以这里也不考虑PureComponent了)来包装你的组件。

const MemoHomeScreen = React.memo(HomeScreen)

说一百句,也顶不上一句代码,具体代码如下(都是可以copy到你的环境中直接运行的):

import React, {useState} from 'react'; import { View, Text, Button } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() const MemoHomeScreen = React.memo(HomeScreen) function App() { const [age, setAge] = useState(20) const homeInst = (props) => (<MemoHomeScreen {...props} />) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App;

上面这段代码的运行效果,和使用component props传递HomeScreen的运行效果一样。只不过前者是使用者自己优化了重绘,后者是Stack Navigator替你优化了。

有因素引起组件更新时,在render callback中使用useCallback

如果我们再稍微多想一下,hostInst本质上是一个function,而说道function的避免重复计算的手段,自然想到了useCallback。我用useCallback来包装一下,看看是否能达到一样的效果:

const homeInst = useCallback((props) => (<HomeScreen {...props} />), [])

完整代码如下:

// In App.js in a new project import React, {useState, useCallback} from 'react' import { View, Text, Button } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' function HomeScreen({ navigation }) { console.log(`home: ${Math.random(new Date().getTime())}`) const goToDetail = () => { navigation.navigate('Details') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title='Go To detail' onPress={goToDetail}></Button> </View> ) } function DetailsScreen({ navigation }) { const goHome = () => { navigation.navigate('Home') } return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title='Go Home' onPress={goHome}></Button> </View> ) } const Stack = createNativeStackNavigator() function App() { const [age, setAge] = useState(20) const homeInst = useCallback((props) => (<HomeScreen {...props} />), []) return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home'> <Stack.Screen name='Home'> {homeInst} </Stack.Screen> <Stack.Screen name='Details' component={DetailsScreen} /> </Stack.Navigator> <View> <Text>{age}</Text> <Button title='Increase Age' onPress={() => (setAge(age + 1))}></Button> </View> </NavigationContainer> ) } export default App

我试了一下,效果和使用React.memo是一样的,都可以达到避免无效重复绘制HomeScreen的目的。

总结

Stack Navigator的使用,除非特殊情况,非得加extraData,否则强烈推荐用props的方式传递组件,减少思维负担。如果要使用render callback,那么我是推荐使用useCallback代替React.memo的,因为配合useCallback的第二个参数,控制起来更加有针对性。

以上就是详解Stack Navigator中使用自定义的Render Callback的详细内容,更多关于Stack Navigator自定义Render Callback的资料请关注易盾网络其它相关文章!