Context解决了什么问题
在一个典型的React应用中,数据是通过props属性逐层传递,这种做法对于某些数据而言是极其繁琐的(如:登录信息、UI主题),这些数据应用中许多组件都需要;而Context提供了一种在组件间共享值的方式,而不必显式地通过组件树逐层传递。
实例演示:应用主题配置
- 分析实现效果,思考传统实现思路及问题
- 对比Context实现方式,体会Context的简洁和解耦
- 使用state维护动态Context值
使用Context的思考
- 因为Context本质上就是全局变量,大量使用Context会导致组件失去独立性,使组件复用性变差。
- 对于常规的组件间传值,可优先考虑组件组合、状态管理、单例导出等方式,不要过度使用Context。
ThemeContext.tsx
import { createContext } from 'react';
export const ThemeContext = createContext<string>('dark');
RootView.js
import React, { useState } from 'react';
import {
View,
Button
} from 'react-native';
import { ThemeContext } from './ThemeContext';
import PageView from './PageView';
export default () => {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Button title='切换主题' onPress={() => {
setTheme(state => {
if (state === 'dark') {
return 'light';
} else {
return 'dark';
}
})
}} />
<View style={{ width: '100%' }}>
<PageView />
</View>
</ThemeContext.Provider>
);
}
PageView.js
import React from 'react';
import {
View,
} from 'react-native';
import Header from './Header';
export default () => {
return (
<View>
<Header />
</View>
);
}
Header.js
import React, { useContext } from 'react';
import {
StyleSheet,
View,
Image,
Text,
} from 'react-native';
import icon_avatar from '../assets/images/default_avatar.png';
import { ThemeContext } from './ThemeContext';
export default () => {
const theme = useContext(ThemeContext);
const styles = theme === 'dark' ? darkStyles : lightStyles;
return (
<View style={styles.content}>
<Image style={styles.img} source={icon_avatar} />
<Text style={styles.txt}>个人信息介绍</Text>
<View style={styles.infoLayout}>
<Text style={styles.infoTxt}>
各位产品经理大家好,我是个人开发者张三,我学习RN两年半了,我喜欢安卓、RN、Flutter。
</Text>
</View>
</View>
);
}
const darkStyles = StyleSheet.create({
content: {
width: '100%',
height: '100%',
backgroundColor: '#353535',
flexDirection: 'column',
alignItems: 'center',
paddingHorizontal: 16,
paddingTop: 64,
},
img: {
width: 96,
height: 96,
borderRadius: 48,
borderWidth: 4,
borderColor: '#ffffffE0',
},
txt: {
fontSize: 24,
color: 'white',
fontWeight: 'bold',
marginTop: 32,
},
infoLayout: {
width: '90%',
padding: 16,
backgroundColor: '#808080',
borderRadius: 12,
marginTop: 24,
},
infoTxt: {
fontSize: 16,
color: 'white',
},
});
const lightStyles = StyleSheet.create({
content: {
width: '100%',
height: '100%',
backgroundColor: '#fafafa',
flexDirection: 'column',
alignItems: 'center',
paddingHorizontal: 16,
paddingTop: 64,
},
img: {
width: 96,
height: 96,
borderRadius: 48,
borderWidth: 4,
borderColor: '#00000080',
},
txt: {
fontSize: 24,
color: '#333333',
fontWeight: 'bold',
marginTop: 32,
},
infoLayout: {
width: '90%',
padding: 16,
backgroundColor: '#EAEAEA',
borderRadius: 12,
marginTop: 24,
},
infoTxt: {
fontSize: 16,
color: '#666666',
},
});