利用context组件数据传递
react的数据传递 是从父级向子级传递的。通过props。如果是很多组件需要的数据,通过props传递会非常麻烦。这个时候可以使用context。
context需要可以类似于store但是也不能滥用。
react-redux的 <Provider /> ,就是通过 Context 提供一个全局态的 store ,路由组件react-router通过 Context 管理路由状态等等。
context适用场景:地区偏好,UI主题
传统实现:
class App extends React.Component { render() { return <Toolbar theme="dark" />; } } function Toolbar(props) { // Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。 // 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事, // 因为必须将这个值层层传递所有组件。 return ( <div> <ThemedButton theme={props.theme} /> </div> ); } class ThemedButton extends React.Component { render() { return <Button theme={this.props.theme} />; } }
创建context对象
const MyContext = React.createContext(defaultValue); 创建一个context对象。设置默认值。
当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider
中读取到当前的 context 值。如果没有Provider就会取默认值。
context.Provider
<MyContext.Provider value={默认值}>
每个context对象都返回一个provider组件
一个provider组件可以和多个消费组件对应关系。
<ThemeContext.Provider value="dark"> <Toolbar /> <ContextTypePage /> //多个组件 </ThemeContext.Provider>
多个provider也可以嵌套,里层会覆盖外层。
import {ThemeContext, UserContext} from "../Context"; export default function UseContextPage(props) { const themeContext = useContext(ThemeContext); const { themeColor } = themeContext; const userContext = useContext(UserContext); return ( <div className="border"> <h3 className={themeColor}>UseContextPage</h3> <p>{userContext.name}</p> </div> ); }
provider值变化 里面所有的消费组件都会渲染。
组件的contextType属性
挂载在 class 上的 contextType
属性会被重赋值为一个 Context 对象。这能让你使用 this.context
来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它。
import {ThemesContext} from './theme-context' export class ThemedButton extends React.Component{ render(){ let props =this.props; let theme =this.context; console.log(theme) return ( <button {...props} style={{backgroundColor:theme.background,color:theme.foreground,width:"200px"}} /> ) } } ThemedButton.contextType=ThemesContext;//这个一定要有
简单的例子:
context实现:
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。 // 为当前的 theme 创建一个 context(“light”为默认值)。 const ThemeContext = React.createContext('light'); class App extends React.Component { render() { // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。 // 无论多深,任何组件都能读取这个值。 // 在这个例子中,我们将 “dark” 作为当前的值传递下去。 return ( <ThemeContext.Provider value="dark"> <Toolbar />
<ContextTypePage /> //多个组件
</ThemeContext.Provider> ); } } // 中间的组件不必指明往下传递 theme 。 function Toolbar() { return ( <div> <ThemedButton /> </div> ); } class ThemedButton extends React.Component { // 指定 contextType 读取当前的 theme context。 // React 会往上找到最近的 theme Provider,然后使用它的值。 // 在这个例子中,当前的 theme 值为 “dark”。 static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
实际应用:
theme-context.js
import React from 'react'; export const themes={ light:{ foreground: '#ffffff', background:"#4DB8C6" }, dark:{ foreground: '#ffffff', background:"#222222" } } export const ThemesContext =React.createContext(themes.dark)
themed-button.js
import React from 'react'; import {ThemesContext} from './theme-context' export class ThemedButton extends React.Component{ render(){ let props =this.props; let theme =this.context; console.log(theme) return ( <button {...props} style={{backgroundColor:theme.background,color:theme.foreground,width:"200px"}} /> ) } } ThemedButton.contextType=ThemesContext;
app.js
function ToolBar1(props){ return ( <ThemedButton onClick={props.changeTheme}> 主题按钮 </ThemedButton> ) } class App extends React.Component{ constructor(props){ super(props); this.state={ theme:themes.light } this.toggleTheme = () => { this.setState(state => ({ theme: state.theme === themes.dark ? themes.light : themes.dark, })); console.log(this.state.theme) }; } render (){ return ( <ThemesContext.Provider value={this.state.theme}> <ToolBar1 changeTheme={this.toggleTheme} /> </ThemesContext.Provider> ) } }
效果图
最好实现主题变动的是 改变类名
写两套css样式 根据不同的类名 进行处理。
react官网 https://react.docschina.org/docs/context.html#when-to-use-context