当前位置: 首页 > 后端技术 > Node.js

Context-React的跨组件访问数据的工具

时间:2023-04-03 17:36:45 Node.js

Context提供了一种跨组件访问数据的方法。它不需要在组件树之间逐层传递属性,也可以方便地访问其他组件的数据。在经典的React应用程序中,数据通过props从父组件传递到子组件。但是在一些特定的场合,需要在各个组件之间共享一些数据。Context为我们提供了一种组件间共享数据的方式,可以避免数据在组件树上层层传递。当使用Context时,Context可以在组件树中的组件之间共享“全局”数据。例如:登录用户信息、用户选择的主题、语言等。在下面的例子中,我们“手动”从上到下传递theme属性来设置Button的样式。classAppextendsReact.Component{render(){return;}}functionToolbar(props){//工具栏组件必须采用额外的“主题”道具//并将其传递给ThemedButton。//如果应用程序中的每个按钮都需要知道主题,这可能会变得很痛苦//因为它必须通过所有组件传递。返回(

);}classThemedButtonextendsReact.Component{render(){return;}}使用Context,我们可以避免通过多个中间组组件传递props//Context让我们将一个值深入到组件树中//无需显式地将它遍历每个组件。//为当前主题创建一个上下文(使用“light"作为默认值).constThemeContext=React.createContext('light');classAppextendsReact.Component{render(){//使用Provider来将当前主题传递给下面的树。//任何组件都可以读取它,无论它有多深。//在这个例子中,我们传递“dark”作为当前值。返回();}}//中间的组件不必//显式地向下传递主题。functionToolbar(props){return(
);}classThemedButtonextendsReact.Component{//分配一个contextType来读取当前的主题上下文。//React会找到上面最接近的主题Provider并使用它的值。//在此示例中,当前主题为“深色”。静态上下文类型=ThemeContext;render(){return;}}有时候,有些数据需要被很多组访问,而且这些组在组树的不同层上Context允许我们以“广播”的形式共享各个组件中的数据变化。上下文相关APIReact.createContextconstMyContext=React.createContext(defaultValue);创建一个新的上下文对象。React在渲染一个组件时,组件注册了一个Context,它会读取父组件中离该组件最近的Provider组件的Context值defaultValue只有在“Consumer”组件找不到Provider组件时才会使用。Context.Provider每个Context对象都带有一个名为Provider的React组件。提供者可以让“消费者”组件监视上下文变化。通过将valueprop传递给Provider的后代Consumer组件,Provider可以与多个Consumer组件建立关系。Provider的value属性更新后,将重新渲染所有后代Consumer组件。此更新从Provider传播到其后代Consumer组件,但不会触发shouldComponentUpdate方法。所以即使Consumer组件的祖先组件没有更新,Consumer组件也会在更新Context的时候使用和Object.is一样的算法来比较value的新旧值来判断它的值是否已经更新注意当传递一个对象给值时,这种判断一个值是否发生变化的方式会导致问题。Please.Class.contextTypeclassMyClassextendsReact.Component{componentDidMount(){letvalue=this.context;/*使用MyContext的值在挂载时执行副作用*/}componentDidUpdate(){letvalue=this.context;/*...*/}componentWillUnmount(){让值=this.context;/*...*/}render(){让值=this.context;/*根据MyContext的值渲染一些东西*/}}MyClass.contextType=MyContext;给类的contextTpe属性赋值一个Context对象后,我们可以在组件的各个生命周期函数中使用this.context获取当前Context对象的方法。一个组件只能注册一个上下文对象。如果您需要读取多个上下文的值,请参与ConsumingMultipleContexts。如果在编码中使用ES实验中的语法,可以使用类的静态(static)成员来初始化contextTYpe。代码如下:classMyClassextendsReact.Component{staticcontextType=MyContext;render(){让值=this.context;/*根据值渲染一些东西*/}}Context.Consumer{value=>/*根据上下文值渲染一些东西*/}Consumer是一个监控上下文的React组件变化。它允许我们监听功能组件中的上下文变化。Consumer组件要求其子元素是一个函数。该函数的参数接收当前上下文的值,要求返回一个React节点(node)。传递给此函数的参数值等于最靠近此Consumer的外部Provider组件的上下文值。如果没有外层Provider组件,则等于调用createContext()时传入的参数值(context的默认值)。注意,关于“一个子元素是一个函数”的更多信息,请参考renderprops栗子嵌套组件中的更新上下文在开发中,我们经常需要更新一些嵌套结构较深的组件的上下文的值。此时,我们可以向下传递一个函数,并用它来更新上下文的值。代码如下:theme-context.js//确保传递给//createContext的默认值的形状与消费者期望的形状匹配!exportconstThemeContext=React.createContext({theme:themes.dark,toggleTheme:()=>{},});theme-toggler-button.jsimport{ThemeContext}from'./theme-context';functionThemeTogglerButton(){//ThemeTogglerButton不仅接收主题//还有一个toggleTheme函数从上下文返回({({theme,toggleTheme})=>(ToggleTheme)});}exportdefaultThemeTogglerButton;app.jsimport{ThemeContext,themes}from'./theme-context';importThemeTogglerButtonfrom'./theme-toggler-button';classAppextendsReact.Component{构造函数(道具){超级(道具);这个.toggleTheme=()=>{this.setState(state=>({theme:state.theme===themes.dark?themes.light:themes.dark,}));};//State还包含更新程序函数,因此它将//传递给上下文提供程序this.state={theme:themes.light,toggleTheme:this.toggleTheme,};}render(){//整个状态被传递给提供者return();}}functionContent(){return(
);}ReactDOM.render(,document.root);使用多个Contexts为了保持React的快速渲染,我们需要将每个消费者组件写成一个独立的组件节点(node)//Themecontext,默认为lightthemeconstThemeContext=React.createContext('light');//登录用户上下文constUserContext=React.createContext({name:'Guest',});应用程序类ndsReact.Component{render(){const{signedInUser,theme}=this.props;//提供初始上下文值的App组件return();}}functionLayout(){return(
);}//一个组件可能会消费多个上下文functionContent(){return({theme=>({user=>()})});}如果超过两个上下文经常一起使用,我们需要考虑创建一个renderprop组件,提供两个Context注意,因为context使用引用标识(referenceidentity)来判断什么时候需要重新渲染,所以在某些情况下,当父元素的提供者被重新渲染,它将触发consumer的非内部渲染,比如下面的代码,每次Provider重新渲染时,都会重新渲染所有的consumer组件。因为总是会创建一个新对象并赋值给值(值一直在变)classAppextendsReact.Component{render(){return();}}为了避免这个问题,你可以把值放在组件的状态中classAppextendsReact.Component{constructor(props){super(props);this.state={value:{something:'something'},};}render(){return();}}