目录

React Native笔记

Q:JSON转JavaScript对象时自定义key

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const jsonString = '{"componentName":"abc","theme":"light","debugMode":"1"}';
const obj = JSON.parse(jsonString, function (k, v) {
  if (k == "theme") {
    // 给自定义的属性赋值
    this.custom = v;
    // 返回undefined会把当前这个key从对象中移除
    return undefined;
  } else if (k == "") {
    console.log("宝儿姐");
  }
  return v;
});

console.log(obj);

Q:对象如何判空?

1
2
3
4
5
let obj;

console.log(obj == null); // true
console.log(obj == undefined); // true
console.log(obj == false); // false

Q:?? 与 || 区别

?? 只有当valuenullundefined时才会取后面的值,而 || 则认为nullundefined0""false 这些都是false

Q:JS数组取值需要注意越界问题吗?

不需要,JS的数组不会发生越界的异常,我们使用时只需关注数组是否 undefined的问题。

1
2
const arr = [];
console.log(arr[0]); // undefined

undefined问题:

/images/reactnative/undefined.webp
undefined

解决办法:

1
2
const arr = undefined;
console.log(arr?.[0]); // undefined

Q:JS中如何判断一个变量是数组还是对象?

1
2
3
4
const arr = [];
const obj = {};

console.log(Array.isArray(arr)); // true

Q: TypeScript中unknownnever

  1. unknown表示不确定的类型,可以赋值给任何类型,但是在使用之前需要进行类型检查,否则在执行函数调用时会报错,而any不需要进行类型检查就可以执行,这点是与any的不同之处。
  2. never可以用作类型检查,同时返回值为never表示它不会有任何的返回值,其中一个场景如下:
    1
    2
    3
    4
    5
    6
    7
    8
    
    function foo(): never {
       const x: number = 999;
       if (x > 0) {
         //⚠️ error
         return;
       }
       console.log(x);
    }
    

参考: TypeScript 中 any、unknown 和 never 完整指南

Q:<> vs React.Fragment

  1. 相同点:
  • 都可以包裹子元素
  • 都不渲染任何真实的DOM标签
  • 性能提升
  1. 不同点:
  • React.Fragment支持设置key属性

Fragment可以解决我们什么问题?

map函数中的组件需要设置key属性,<> 并不支持设置属性,而我们又不想增加DOM节点,此时React.Fragment就可以大展身手了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<Text style={style} numberOfLines={numberOfLines}>
    {icons?.map(({ width, height, url }, index) => {
        return (
            <React.Fragment key={index.toString()}>
                <Image
                    style={styles.iconImg}
                    resizeMode={'contain'}
                    source={{
                        uri: url,
                    }}
                />
                <Text>&nbsp;</Text>
            </React.Fragment>
        );
    })}

    {props.children ?? ''}
</Text>

Q:hook函数不让在函数中使用怎么办?

使用useMutation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
export function useQueryProviderNextPage() {
    const bookId = 123
    const dispatch = useAppDispatch();
    return useMutation(
        (params: IParams) => {
            return request({
                method: 'POST',
                url: '/a/b/c',
                params: {
                    id: bookId,
                    currentPage: params.currentPage ?? 2,
                },
            });
        },
        {
            onSuccess: (response) => {
                if (response) {
                    dispatch(updateProviderList(response.data));
                }
            },
            onError: (response) => {
                console.log('--- 请求失败---', console.log(JSON.stringify(response)));
            },
        },
    );
}

const fetchNextPageMutation = useQueryNextPage();

// 调用
fetchNextPageMutation.mutate({
    currentPage: (section?.currentPage ?? 1) + 1,
	bookId: section?.id,
});

Q:ListEmptyComponets 不能铺满:

SectionList设置contentContainerStyle属性:

1
2
3
4
5
<SectionList
  contentContainerStyle={{
    flexGrow: 1,
  }}
/>

Q:条件渲染

React 中条件渲染的 N 种方法

在写组件时不要用{ 判断条件 && 组件 }这种写法,因为假如前面的条件是false,那这个结果就是 { false } ,然而这并不是一个合法的组件,在某些场景下会报错。建议使用{ 判断条件 ? 组件 : null }这种方式。

Q: 切圆角时如何把子类超出父视图的部分也切掉?

确保父元素的overflow属性设置为hidden

1
2
3
{
  overflow: "hidden";
}

Q: 如何让文字纵向居中?

  1. View组件包一层
  2. 设置lineHeight与控件高度相同
1
<Text style={{ textAlign: "center", lineHeight: 40 }}>文本内容</Text>

Q: 如何让视图不响应事件?

1
<View pointerEvents="none" />

Q: 有哪些实用API?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import {
  useWindowDimensions,
  NativeModules,
  StatusBar,
  Platform,
} from "react-native";

const { StatusBarManager } = NativeModules;

const windowWidth = useWindowDimensions().width;
const windowHeight = useWindowDimensions().height;

export const STATUS_BAR_HEIGHT =
  Platform.OS === "android" ? StatusBar.currentHeight : StatusBarManager.HEIGHT;

// Platform.select
const styles = StyleSheet.create({
  container: {
    marginTop: Platform.OS === "android" ? 25 : 0,
  },
  text: {
    ...Platform.select({
      ios: { color: "purple", fontSize: 24 },
      android: { color: "blue", fontSize: 30 },
    }),
    fontWeight: "bold",
    textAlign: "center",
  },
});

Q: redux中一个reducer想读取其他reducer数据怎么办?

使用 extraReducers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
export const xxxReducer = createSlice({
    name: 'xxxReducer',
    initialState: {
        data: undefined as IProp,
        show: false,
        enable: false,
    },
    reducers: {
        updateIPropInfo: (state, action: PayloadAction<IProp>) => {
            state.data = action.payload;
        },
        updateClockInLoadingStatus: (state, action: PayloadAction<boolean>) => {
            state.show = action.payload;
        },
    },
    // 在这里截获其他reducer中的数据,
    // 如下面的updateDetailData就是来自其他reducer
+    extraReducers: (builder) => {
+        builder.addCase(
+           updateDetailData,
+            (state, action: PayloadAction<DetailResponse>) => {
+                const model = action.payload?.data;
+                state.enable = model?.enable === 1;
+            },
+        );
+    },
});

useInfiniteQuery用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
export interface IBaseResponse<T> {
    [propName: string]: any;
    message?: string;
    code?: string;
    data: T;
}

export function useQueryXXList() {
    const dispatch = useDispatch();
    const currentPageCount = useAppSelector(selectCurrentPageCount);

    return useInfiniteQuery<XXResponse>(
        ['a', 'b'],
        (params) => {
            return requestXXList({ cursor: params?.pageParam });
        },
        {
            onSuccess: (data) => {
                const listCount = data?.pages?.length ?? 0;
                if (currentPageCount == listCount) {
                    return;
                }
                if (listCount > 0) {
                    const xxData = data?.pages?.[listCount - 1]?.data;
                    dispatch(updateXXListData(xxData));
                } 
            },
            onError: (error) => {
                console.log(error);
            },
            getNextPageParam: (
                lastPage: IBaseResponse<XXListData>,
                _pages,
            ) => {
                if (lastPage?.data?.nextCursor !== 'XX') {
                    return lastPage?.data?.nextCursor;
                }
                // 没有更多数据
                return undefined;
            },
        },
    );
}