这篇博客记录实习的所见所闻1
- 在
React Native Navigation
中,headerBackImage
是一个可选的属性,headerBackImage
属性最早出现在 @react-navigation/stack 5.0.0
版本中。在此之前,该属性可以通过使用 headerLeft
和自定义返回按钮组件来实现。,用于自定义路由堆栈导航栏中返回按钮的图像。默认情况下,返回按钮会显示操作系统的默认返回箭头图标。
- 如果你想要使用自己的图标来代替默认返回箭头,可以在创建
StackNavigator
时为每个StackNavigator
或者每个具有独立header
的screen
设置 headerBackImage
属性。
- 例如,你可以通过以下方式在整个
stack navigator
上设置该属性:
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
function App() { return ( <Stack.Navigator screenOptions={{ headerBackImage: () => ( <Image source={require('./path/to/your/image')} style={{ width: 20, height: 20 }} /> ), }} > {/* Screens */} </Stack.Navigator> ); }
|
import { useNavigation } from '@react-navigation/native';
function MyScreen() { const navigation = useNavigation();
React.useLayoutEffect(() => { navigation.setOptions({ headerBackImage: () => ( <Image source={require('./path/to/your/image')} style={{ width: 20, height: 20 }} /> ), }); }, [navigation]);
|
需要注意的是,headerBackImage
只影响路由堆栈导航栏的返回按钮图标,并不影响手势和其他返回交互的行为。
2.static
在类组件中的作用是什么?(react-native/react
)
- 在
React
的类组件中,static
关键字用于定义静态属性或静态方法。这些属性或方法不会被实例化对象所继承,而是直接属于类本身。因此,它们可以在任何地方被访问,无需创建类的实例。
在类组件中,static
可以在以下场景下使用:
- 1.定义静态属性
- 静态属性是指属于类本身而非实例对象的属性,可以通过类名直接访问。例如,你可以在一个
React
类组件中定义一个静态属性来存储组件的一些默认状态:**class MyComponent extends React.Component { static defaultProps = { count: 0, }
}
|
- 定义静态方法
- 静态方法是指属于类本身而非实例对象的方法,可以通过类名直接调用。例如,你可以在一个
React
类组件中定义一个静态方法来实现一些通用的逻辑:class MyComponent extends React.Component { static doSomething() { }
}
|
需要注意的是,由于静态方法和静态属性是属于类本身而非实例对象的,所以你不能在这些静态成员中访问 this
,并且无法访问实例对象的属性或方法。
3.navigationOptions
结合static
在类组件中的使用以及为什么一定要结合static
来使用才能在类组件内部配置navigationOptions
(React-native
)
navigationOptions
是 React Navigation
中用于配置页面导航选项的属性,它可以被设置为一个对象或一个返回对象的函数。在函数组件中,我们可以使用 useNavigationOptions
钩子来动态配置导航选项。而在类组件中,由于缺乏钩子这种函数式编程的特性,我们需要使用static
关键字来定义静态属性。
- 具体地说,当你在类组件中定义一个
navigationOptions
对象时,这个对象是作为该类的实例属性存在的。而当你在一个屏幕中使用这个类时,React Navigation
会利用这个对象来设置导航栏等选项。但是,如果你不使用static
关键字来定义这个对象,这个对象会成为该类所有实例的共享属性,这可能会导致一些意外的问题。
- 通过使用
static
关键字,你可以确保 navigationOptions
对象只属于该类本身而非该类的实例对象,并且不受到其他实例对象的影响。这样,在不同的屏幕中使用相同的类时,每个屏幕都可以有自己独立的导航选项。
- 在
React Navigation
组件中,可以使用 navigationOptions
属性来配置屏幕的导航选项。而在类组件中,可以结合 static
关键字使用 navigationOptions
来定义静态属性。
例如,在一个使用 createStackNavigator
创建的堆栈导航中,你可以在类组件中定义 navigationOptions
静态属性来配置页面的标题:
class HomeScreen extends React.Component { static navigationOptions = { title: 'Home', };
}
|
在上面的例子中,navigationOptions
是一个静态属性,它的值是一个对象,包含了要设置的选项,比如 title
。这个静态属性会被堆栈导航器用于生成页面的导航栏,显示为一个标题为 "Home"
的页面。
需要注意的是,在类组件中定义 navigationOptions
静态属性时,它只能访问到类本身的静态成员,不能访问实例对象的属性或方法。如果你需要访问实例对象的属性或方法,可以在渲染方法中使用this.props
和 this.state
来获取。
4.使用函数式组件中的useEffect
钩子模拟类组件中的所有生命周期
- 当使用函数式组件时,可以使用
useEffect
钩子来模拟类组件中的各个生命周期方法。下面是一些常见的情况以及如何用useEffect
来模拟它们:
1.模拟 componentDidMount
- 在类组件中,componentDidMount 是在组件挂载后调用的生命周期方法,可以在其中做一些初始化操作。在函数式组件中,可以使用 useEffect 来实现相同的功能:
useEffect(() => { }, []);
|
2.模拟 componentDidUpdate
- 在类组件中,
componentDidUpdate
是在组件更新后调用的生命周期方法,可以在其中进行一些副作用操作。在函数式组件中,也可以使用 useEffect
来模拟 componentDidUpdate
:
···js useEffect(() => { }, [props.someProp]);
|
3.模拟 componentWillUnmount
- 在类组件中,
componentWillUnmount
是在组件卸载前调用的生命周期方法,可以在其中进行一些清理操作。在函数式组件中,也可以使用 useEffect
来模拟 componentWillUnmount:
useEffect(() => { return () => { }; }, []);
|
在这个例子中,我们在useEffect
中返回一个函数,这个函数会在组件卸载时被调用。这与 componentWillUnmount
的行为相似。需要注意的是,useEffect
和类组件中的生命周期不完全等价,因为它们有一些细微的差别。例如,在类组件中,可以取消更新或者阻止组件重新渲染,但在函数式组件中则不能这样做。因此,在实现功能相同时,应该根据具体情况选择合适的方式。
5.usememo
结合useEffect
来实现子组件更新但父组件不更新的操作
- 在
React
中,可以使用 useMemo
钩子来缓存计算结果,并且只有在依赖项发生变化时才重新计算。结合 useEffect
,我们可以实现子组件更新但父组件不更新的操作。
- 具体地说,我们可以在父组件中使用
useMemo
缓存需要传递给子组件的数据,并将这个数据作为依赖项传递给 useEffect
。这样,在子组件更新时,useMemo
的缓存数据不会失效,只有在父组件更新时才会重新计算。
import { useState, useMemo, useEffect } from 'react'; import ChildComponent from './ChildComponent';
function ParentComponent(props) { const [count, setCount] = useState(0); const memoizedData = useMemo(() => { return { count, someProp: props.someProp, }; }, [ props.someProp]);
useEffect(() => { console.log('memoizedData has changed:', memoizedData); }, [memoizedData]);
return ( <div> <button onClick={() => setCount(count + 1)}> Click me ({count}) </button> <ChildComponent data={memoizedData} /> </div> ); }
|
在这个例子中,我们定义了一个 ParentComponent
父组件和一个 ChildComponent
子组件。在 ParentComponent
中,我们使用 useState
定义了一个状态变量 count
,并在按钮的点击事件中更新这个变量。我们还使用 useMemo
缓存了需要传递给子组件的数据,并将这个数据作为依赖项传递给了 useEffect
。在 ChildComponent
中,我们只是简单地输出父组件传递过来的数据。
当你运行这个代码时,你会发现每次在父组件中点击按钮更新 count
变量时,控制台打印的消息仅仅是子组件更新了,而父组件没有更新。这是因为我们使用了 useMemo
来缓存需要传递给子组件的数据,并且只有在count
或 props.someProp
变化时才会重新计算缓存数据。
需要注意的是,在实际开发中,如果你想要避免不必要的渲染,应该尽可能地将 useMemo
和 useCallback
应用到所有合适的地方,并使用合适的依赖项来控制它们的触发时机。
6.讲讲useCallback和useMemo的区别
useCallback
和 useMemo
都是 React
中的钩子函数,用于优化性能和避免不必要的重新渲染。虽然它们有一些相似之处,但它们的作用和使用方法有所不同。
useCallback
的作用是在函数组件的渲染周期内缓存回调函数,并且只有在某个依赖项改变时才重新创建这个回调函数。这样,在父组件需要向子组件传递回调函数时,可以使用 useCallback
来确保子组件不会因为父组件的重新渲染而不必要地更新。
import { useState, useCallback } from 'react';
function ParentComponent() { const [count, setCount] = useState(0);
const handleClick = useCallback(() => { console.log('Button clicked!'); }, []);
return ( <div> <button onClick={() => setCount(count + 1)}> Click me ({count}) </button> <ChildComponent onClick={handleClick} /> </div> ); }
function ChildComponent(props) { return <button onClick={props.onClick}>Click me</button>; }
|
在这个例子中,我们定义了一个 ParentComponent
父组件和一个 ChildComponent
子组件。在 ParentComponent
中,我们使用 useState
定义了一个状态变量 count
,并在按钮的点击事件中更新这个变量。我们还使用 useCallback
缓存了一个回调函数 handleClick
,并将它传递给了子组件 ChildComponent
。在ChildComponent
中,我们只是简单地输出父组件传递过来的回调函数。
useMemo
的作用是在函数组件的渲染周期内缓存计算结果,并且只有在某个依赖项改变时才重新计算这个结果。这样,在某些昂贵的计算场景下,可以使用 useMemo
来避免重复计算。下面是一个示例代码:
import { useMemo } from 'react';
function MyComponent(props) { const memoizedValue = useMemo(() => { return props.someProp * 2; }, [props.someProp]);
return <div>The value is {memoizedValue}.</div>; }
|
在这个例子中,我们定义了一个 MyComponent
函数组件,并使用 useMemo
缓存了一个计算结果 memoizedValue
。在 useMemo
的回调函数中,我们进行了一些昂贵的计算,并将结果返回给 useMemo
。我们还将 props.someProp
作为依赖项传递给了 useMemo
,以确保只有在这个属性变化时才会重新计算缓存数据。
总的来说,useCallback
和 useMemo
都是用于优化性能和避免不必要的重新渲染的工具。它们的主要区别在于应用场景和使用方法。如果你需要缓存一个回调函数并将它传递给子组件,那么可以使用 useCallback
;如果你需要缓存一些计算结果并在渲染周期内重复使用,那么可以使用 useMemo
。
7. 在react
中的函数式组件hooks
:useState
只能一次处理一个状态吗?那如果在这个组件中我要维护多个状态呢?每一次更新多个状态都要调用一次对应的更新方法,这样不是造成了多次渲染组件吗?如何解决这个问题?
- 在
React
中的函数式组件中,useState
钩子只能处理一个状态。如果要维护多个状态,则需要使用多个useState
钩子。如果在组件中需要维护的状态较多,而且频繁地更新这些状态可能会导致性能问题,可以考虑使用 useReducer
钩子来替代 useState
钩子。useReducer
可以将多个状态合并为一个状态对象,并提供了一种更加灵活的状态管理方式。例如:
import { useReducer } from 'react';
function reducer(state, action) { switch (action.type) { case 'UPDATE_NAME': return { ...state, name: action.payload }; case 'UPDATE_AGE': return { ...state, age: action.payload }; default: throw new Error(); } }
function MyComponent() { const [state, dispatch] = useReducer(reducer, { name: 'Alice', age: 20, });
const handleClick = () => { dispatch({ type: 'UPDATE_NAME', payload: 'Bob' }); dispatch({ type: 'UPDATE_AGE', payload: 30 }); };
return ( <div> <p>Name: {state.name}</p> <p>Age: {state.age}</p> <button onClick={handleClick}>Update</button> </div> ); }
|
在这个例子中,我们使用了 useReducer
钩子并定义了一个 reducer
函数来处理多个状态的更新操作。需要注意的是,在使用 useReducer
时,每次调用 dispatch
函数都会触发一次组件重新渲染,因此也应该避免频繁地更新状态。