diff --git a/cndocs/animated.md b/cndocs/animated.md index 8c1955be494..0e0858f870f 100644 --- a/cndocs/animated.md +++ b/cndocs/animated.md @@ -188,15 +188,15 @@ Animated.timing({}).start(({finished}) => { 例如在横向滚动中,将 `event.nativeEvent.contentOffset.x` 映射到 `scrollX`(一个 `Animated.Value`): ```tsx - onScroll={Animated.event( - // scrollX = e.nativeEvent.contentOffset.x - [{nativeEvent: { - contentOffset: { - x: scrollX - } - } - }] - )} +onScroll={Animated.event( + // scrollX = e.nativeEvent.contentOffset.x + [{ + nativeEvent: { + contentOffset: {x: scrollX}, + }, + }], + {useNativeDriver: true}, +)} ``` --- diff --git a/cndocs/animatedvaluexy.md b/cndocs/animatedvaluexy.md index 3fca29425f2..6be07a0d99d 100644 --- a/cndocs/animatedvaluexy.md +++ b/cndocs/animatedvaluexy.md @@ -17,13 +17,16 @@ const DraggableView = () => { const panResponder = PanResponder.create({ onStartShouldSetPanResponder: () => true, - onPanResponderMove: Animated.event([ - null, - { - dx: pan.x, // x,y are Animated.Value - dy: pan.y, - }, - ]), + onPanResponderMove: Animated.event( + [ + null, + { + dx: pan.x, // x,y are Animated.Value + dy: pan.y, + }, + ], + {useNativeDriver: false}, + ), onPanResponderRelease: () => { Animated.spring( pan, // Auto-multiplexed diff --git a/cndocs/animations.md b/cndocs/animations.md index 08e6bbaac8f..1acedbd9779 100644 --- a/cndocs/animations.md +++ b/cndocs/animations.md @@ -293,15 +293,15 @@ Animated.timing(opacity, { 例如,在使用水平滚动手势时,您可以执行以下操作,以便将“event.nativeEvent.contentOffset.x”映射到“scrollX”(“Animated.Value”): ```tsx - onScroll={Animated.event( - // scrollX = e.nativeEvent.contentOffset.x - [{nativeEvent: { - contentOffset: { - x: scrollX - } - } - }] - )} +onScroll={Animated.event( + // scrollX = e.nativeEvent.contentOffset.x + [{ + nativeEvent: { + contentOffset: {x: scrollX}, + }, + }], + {useNativeDriver: true}, +)} ``` 以下示例实现了水平滚动轮播,其中滚动位置指示器使用“ScrollView”中使用的“Animated.event”进行动画处理 @@ -338,15 +338,18 @@ const App = () => { horizontal={true} pagingEnabled showsHorizontalScrollIndicator={false} - onScroll={Animated.event([ - { - nativeEvent: { - contentOffset: { - x: scrollX, + onScroll={Animated.event( + [ + { + nativeEvent: { + contentOffset: { + x: scrollX, + }, }, }, - }, - ])} + ], + {useNativeDriver: true}, + )} scrollEventThrottle={1}> {images.map((image, imageIndex) => { return ( @@ -459,7 +462,9 @@ const App = () => { const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder: () => true, - onPanResponderMove: Animated.event([null, {dx: pan.x, dy: pan.y}]), + onPanResponderMove: Animated.event([null, {dx: pan.x, dy: pan.y}], { + useNativeDriver: false, + }), onPanResponderRelease: () => { Animated.spring(pan, { toValue: {x: 0, y: 0}, diff --git a/cndocs/appstate.md b/cndocs/appstate.md index cc095dc8684..9d40a6912f9 100644 --- a/cndocs/appstate.md +++ b/cndocs/appstate.md @@ -38,7 +38,7 @@ const AppStateExample = () => { useEffect(() => { const subscription = AppState.addEventListener('change', nextAppState => { if ( - appState.current.match(/inactive|background/) && + appState.current?.match(/inactive|background/) && nextAppState === 'active' ) { console.log('App has come to the foreground!'); diff --git a/cndocs/dimensions.md b/cndocs/dimensions.md index 8ead0fc76d6..6cf15ee4878 100644 --- a/cndocs/dimensions.md +++ b/cndocs/dimensions.md @@ -26,9 +26,14 @@ const windowHeight = Dimensions.get('window').height; ## 示例 -```SnackPlayer name=Dimensions%20Example +```SnackPlayer name=Dimensions%20Example&ext=tsx import {useState, useEffect} from 'react'; -import {StyleSheet, Text, Dimensions} from 'react-native'; +import { + StyleSheet, + Text, + Dimensions, + type DimensionsPayload, +} from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; const windowDimensions = Dimensions.get('window'); @@ -43,8 +48,10 @@ const App = () => { useEffect(() => { const subscription = Dimensions.addEventListener( 'change', - ({window, screen}) => { - setDimensions({window, screen}); + ({window, screen}: DimensionsPayload) => { + if (window && screen) { + setDimensions({window, screen}); + } }, ); return () => subscription?.remove(); diff --git a/cndocs/drawerlayoutandroid.md b/cndocs/drawerlayoutandroid.md index b0e97ef4de7..8e6406394fb 100644 --- a/cndocs/drawerlayoutandroid.md +++ b/cndocs/drawerlayoutandroid.md @@ -95,8 +95,12 @@ import { View, } from 'react-native'; +type DrawerLayoutAndroidInstance = React.ComponentRef< + typeof DrawerLayoutAndroid +>; + const App = () => { - const drawer = useRef(null); + const drawer = useRef(null); const [drawerPosition, setDrawerPosition] = useState<'left' | 'right'>( 'left', ); diff --git a/cndocs/flexbox.md b/cndocs/flexbox.md index 9ebae4deb6f..1b9e596f9e2 100644 --- a/cndocs/flexbox.md +++ b/cndocs/flexbox.md @@ -985,12 +985,17 @@ export default AlignSelfLayout; ```SnackPlayer name=Align%20Self&ext=tsx import {useState} from 'react'; -import {View, TouchableOpacity, Text, StyleSheet} from 'react-native'; +import { + View, + TouchableOpacity, + Text, + StyleSheet, + type ViewStyle, +} from 'react-native'; import type {PropsWithChildren} from 'react'; -import type {FlexAlignType} from 'react-native'; const AlignSelfLayout = () => { - const [alignSelf, setAlignSelf] = useState('stretch'); + const [alignSelf, setAlignSelf] = useState('stretch'); return ( { type PreviewLayoutProps = PropsWithChildren<{ label: string; - values: FlexAlignType[]; - selectedValue: string; - setSelectedValue: (value: FlexAlignType) => void; + values: ViewStyle['alignSelf'][]; + selectedValue: ViewStyle['alignSelf']; + setSelectedValue: (value: ViewStyle['alignSelf']) => void; }>; const PreviewLayout = ({ diff --git a/cndocs/improvingux.md b/cndocs/improvingux.md index cca1cf93af6..27d456609fc 100644 --- a/cndocs/improvingux.md +++ b/cndocs/improvingux.md @@ -125,8 +125,10 @@ import { StyleSheet, } from 'react-native'; +type TextInputInstance = React.ComponentRef; + const App = () => { - const emailInput = useRef(null); + const emailInput = useRef(null); const [name, setName] = useState(''); const [email, setEmail] = useState(''); @@ -325,8 +327,10 @@ import { StyleSheet, } from 'react-native'; +type TextInputInstance = React.ComponentRef; + const App = () => { - const emailInput = useRef(null); + const emailInput = useRef(null); const [email, setEmail] = useState(''); const submit = () => { diff --git a/cndocs/layout-props.md b/cndocs/layout-props.md index acbf9c8775c..442c0b6a153 100644 --- a/cndocs/layout-props.md +++ b/cndocs/layout-props.md @@ -197,8 +197,7 @@ import { StyleSheet, Text, View, - FlexAlignType, - FlexStyle, + ViewStyle, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; @@ -217,7 +216,7 @@ const App = () => { alignItems: alignItemsArr[alignItems], direction: directions[direction], flexWrap: wraps[wrap], - } as FlexStyle; + }; const changeSetting = ( value: number, @@ -307,29 +306,29 @@ const App = () => { ); }; -const flexDirections = [ +const flexDirections: ViewStyle['flexDirection'][] = [ 'row', 'row-reverse', 'column', 'column-reverse', -] as FlexStyle['flexDirection'][]; -const justifyContents = [ +]; +const justifyContents: ViewStyle['justifyContent'][] = [ 'flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly', -] as FlexStyle['justifyContent'][]; -const alignItemsArr = [ +]; +const alignItemsArr: ViewStyle['alignItems'][] = [ 'flex-start', 'flex-end', 'center', 'stretch', 'baseline', -] as FlexAlignType[]; -const wraps = ['nowrap', 'wrap', 'wrap-reverse']; -const directions = ['inherit', 'ltr', 'rtl']; +]; +const wraps: ViewStyle['flexWrap'][] = ['nowrap', 'wrap', 'wrap-reverse']; +const directions: ViewStyle['direction'][] = ['inherit', 'ltr', 'rtl']; const styles = StyleSheet.create({ container: { diff --git a/cndocs/legacy/direct-manipulation.md b/cndocs/legacy/direct-manipulation.md index 6b8cd1eea29..4cc909c3f40 100644 --- a/cndocs/legacy/direct-manipulation.md +++ b/cndocs/legacy/direct-manipulation.md @@ -136,13 +136,16 @@ export default App; ```SnackPlayer name=Forwarding%20setNativeProps&ext=tsx +import {forwardRef, ElementRef} from 'react'; import {Text, TouchableOpacity, View} from 'react-native'; -const MyButton = React.forwardRef((props, ref) => ( - - {props.label} - -)); +const MyButton = forwardRef, {label: string}>( + (props, ref) => ( + + {props.label} + + ), +); const App = () => ( @@ -224,8 +227,10 @@ import { View, } from 'react-native'; +type TextInputInstance = React.ComponentRef; + const App = () => { - const inputRef = useRef(null); + const inputRef = useRef(null); const editText = useCallback(() => { inputRef.current?.setNativeProps({text: 'Edited Text'}); }, []); @@ -374,9 +379,12 @@ type Measurements = { height: number; }; +type TextInstance = React.ComponentRef; +type ViewInstance = React.ComponentRef; + const App = () => { - const textContainerRef = useRef(null); - const textRef = useRef(null); + const textContainerRef = useRef(null); + const textRef = useRef(null); const [measure, setMeasure] = useState(null); useEffect(() => { diff --git a/cndocs/linking.md b/cndocs/linking.md index ca245fa1422..5b0200f338f 100644 --- a/cndocs/linking.md +++ b/cndocs/linking.md @@ -340,7 +340,7 @@ const useInitialURL = () => { // The setTimeout is just for testing purpose setTimeout(() => { - setUrl(initialUrl); + setUrl(initialUrl ?? null); setProcessing(false); }, 1000); }; @@ -394,7 +394,7 @@ const useInitialURL = () => { // The setTimeout is just for testing purpose setTimeout(() => { - setUrl(initialUrl); + setUrl(initialUrl ?? null); setProcessing(false); }, 1000); }; diff --git a/cndocs/panresponder.md b/cndocs/panresponder.md index 75659190bf6..b1be77259b1 100644 --- a/cndocs/panresponder.md +++ b/cndocs/panresponder.md @@ -97,7 +97,9 @@ const App = () => { const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder: () => true, - onPanResponderMove: Animated.event([null, {dx: pan.x, dy: pan.y}]), + onPanResponderMove: Animated.event([null, {dx: pan.x, dy: pan.y}], { + useNativeDriver: false, + }), onPanResponderRelease: () => { pan.extractOffset(); }, diff --git a/cndocs/progressbarandroid.md b/cndocs/progressbarandroid.md index 6cb300d80a5..0f6489074e9 100644 --- a/cndocs/progressbarandroid.md +++ b/cndocs/progressbarandroid.md @@ -19,15 +19,19 @@ const App = () => { Circle Progress Indicator - + Horizontal Progress Indicator - + Colored Progress Indicator - + Fixed Progress Value diff --git a/cndocs/statusbar.md b/cndocs/statusbar.md index b822368d5d3..4ede9b7c385 100644 --- a/cndocs/statusbar.md +++ b/cndocs/statusbar.md @@ -26,7 +26,7 @@ import { } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; -const STYLES = ['default', 'dark-content', 'light-content']; +const STYLES = ['default', 'auto', 'dark-content', 'light-content']; const TRANSITIONS = ['fade', 'slide', 'none']; const App = () => { @@ -134,7 +134,7 @@ import { } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; -const STYLES = ['default', 'dark-content', 'light-content'] as const; +const STYLES = ['default', 'auto', 'dark-content', 'light-content'] as const; const TRANSITIONS = ['fade', 'slide', 'none'] as const; const App = () => { @@ -409,8 +409,9 @@ iOS 上状态栏的过渡动画类型。 **常量:** -| 值 | 类型 | 描述 | -| ----------------- | ------ | -------------------------------------------- | -| `'default'` | string | 默认状态栏样式(iOS 为深色,Android 为浅色) | -| `'light-content'` | string | 白色文字和图标 | -| `'dark-content'` | string | 深色文字和图标(Android 上需要 API>=23) | +| 值 | 类型 | 描述 | +| ----------------- | ------ | -------------------------------------------------------------------------------------- | +| `'default'` | string | 默认状态栏样式(Android 为浅色,iOS 为深色) | +| `'auto'` | string | 根据当前配色方案自动选择 `light-content` 或 `dark-content`,并会在配色方案变化时更新。 | +| `'light-content'` | string | 白色文字和图标 | +| `'dark-content'` | string | 深色文字和图标(Android 上需要 API>=23) | diff --git a/cndocs/stylesheet.md b/cndocs/stylesheet.md index f0b90833b5e..c9afe535dce 100644 --- a/cndocs/stylesheet.md +++ b/cndocs/stylesheet.md @@ -60,7 +60,7 @@ static compose(style1: Object, style2: Object): Object | Object[]; 将两个样式组合在一起,使得 `style2` 会覆盖 `style1` 中的任何样式。如果其中任何一个样式为 falsy,则直接返回另一个,不会分配数组,从而节省内存分配并保持 PureComponent 检查的引用相等性。 -```SnackPlayer name=Compose +```SnackPlayer name=Compose&ext=js import {StyleSheet, Text} from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; diff --git a/cndocs/text-style-props.md b/cndocs/text-style-props.md index 0a863554f03..2c522a81b89 100644 --- a/cndocs/text-style-props.md +++ b/cndocs/text-style-props.md @@ -27,7 +27,6 @@ import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; const fontStyles = ['normal', 'italic']; const fontVariants = [ - undefined, 'small-caps', 'oldstyle-nums', 'lining-nums', @@ -628,7 +627,7 @@ const CustomSlider = ({ type CustomPickerProps = { label: string; - data?: ArrayLike | null; + data?: ArrayLike | undefined; currentIndex: number; onSelected: (index: number) => void; }; @@ -676,7 +675,6 @@ const CustomPicker = ({ const fontStyles = ['normal', 'italic']; const fontVariants = [ - undefined, 'small-caps', 'oldstyle-nums', 'lining-nums', diff --git a/cndocs/the-new-architecture/direct-manipulation.md b/cndocs/the-new-architecture/direct-manipulation.md index 6035b6a64b7..c549f6866fe 100644 --- a/cndocs/the-new-architecture/direct-manipulation.md +++ b/cndocs/the-new-architecture/direct-manipulation.md @@ -82,8 +82,10 @@ import { View, } from 'react-native'; +type TextInputInstance = React.ComponentRef; + const App = () => { - const inputRef = useRef(null); + const inputRef = useRef(null); const editText = useCallback(() => { inputRef.current?.setNativeProps({text: 'Edited Text'}); }, []); diff --git a/cndocs/view-style-props.md b/cndocs/view-style-props.md index ed9afbe56eb..f57fd07ecf0 100644 --- a/cndocs/view-style-props.md +++ b/cndocs/view-style-props.md @@ -117,6 +117,67 @@ export default App; --- +### `backgroundPosition` + +控制背景渐变在视图内部的位置。当设置了 `backgroundImage` 时,可用它偏移或居中渐变,而不是让渐变填满整个区域。 + +```tsx + +``` + +| 类型 | +| ------------------------------------------------------------------------------- | +| string \| 对象数组 `{top: string, left: string, right: string, bottom: string}` | + +--- + +### `backgroundRepeat` + +控制背景渐变是否以及如何重复。它与 `backgroundImage` 配合使用,以平铺视图中的渐变。 + +```tsx + +``` + +| 类型 | +| ------------------------------------------------------------------------------------------ | +| enum(`'repeat'`, `'space'`, `'round'`, `'no-repeat'`) \| 对象数组 `{x: string, y: string}` | + +--- + +### `backgroundSize` + +控制背景渐变的尺寸。当设置了 `backgroundImage` 且渐变默认不应填满整个视图时,此属性尤其有用。 + +```tsx + +``` + +| 类型 | +| ------------------------------------------- | +| string \| 对象数组 `{x: number, y: number}` | + +--- + ### `borderBottomColor` | 类型 | diff --git a/cnwebsite/package.json b/cnwebsite/package.json index d4ff96df383..6701e361e14 100644 --- a/cnwebsite/package.json +++ b/cnwebsite/package.json @@ -67,7 +67,7 @@ "@react-native-website/lint-examples": "*", "@signalwire/docusaurus-plugin-llms-txt": "^1.2.2", "@types/google.analytics": "^0.0.46", - "@types/react": "^19.2.17", + "@types/react": "19.2.17", "eslint": "^9.39.4", "glob": "^13.0.6", "prettier": "^3.9.6",