Context-React如何跨组件访问数据

技术Context-React如何跨组件访问数据这篇文章给大家分享的是有关Context-React如何跨组件访问数据的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。  Context提供了一种

这篇文章给大家分享的是有关上下文-反应如何跨组件访问数据的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

语境提供了一种跨组件访问数据的方法。它无需在组件树间逐层传递属性,也可以方便的访问其他组件的数据

在经典的反应应用中,数据是父组件通过小道具向子组件传递的。但是在某些特定场合,有些数据需要在各个组件之间共享背景为我们提供一种组件之间共享数据的方式,可以避免数据在组件树上逐层传递

使用语境的场合

语境可以在组件树的组件之间共享"全局"数据。例如:登陆的用户信息,用户选择的主题、语言等等。下面的例子中,我们"手动"自上而下传递主题属性,用来设定纽扣的样式。

类应用扩展了做出反应.组件{

render(){ 0

返回工具栏主题='深色'/工具栏;

}

}

功能工具栏(道具){ 0

//工具栏组件必须有一个额外的"主题"道具

//并将其传递给主题按钮。这会变得很痛苦

//如果应用程序中的每个按钮都需要知道主题

//因为它必须通过所有组件。

返回(

差异

主题按钮主题={道具。主题}/主题按钮

/div

);

}

类主题按钮扩展了反应。组件{

render(){ 0

返回按钮主题={这个。道具。主题}/按钮;

}

}

使用背景,我们可以避免通过多个中间组件传递小道具

//上下文允许我们将一个值深入传递到组件树//,而无需显式地将它穿入每个组件。//为当前主题创建上下文(默认为"光")。const主题上下文=react。创建上下文(“光”);

类应用扩展了做出反应.组件{

render(){ 0

//使用提供程序将当前主题传递给下面的树。

//任何组件都可以读取,无论它有多深。

//在本例中,我们将"暗"作为当前值。

返回(

主题上下文。提供者值='暗'

工具栏/工具栏

/主题上下文.供应者

);

}

}

//中间的组件不必

//不再明确传递主题。

功能工具栏(道具){ 0

返回(

差异

按钮/

/div

);

}

类主题按钮扩展了反应。组件{

//分配一个上下文类型来读取当前主题上下文。

//反应会找到上面最接近的主题提供商,并使用它的值。

//在本例中,当前主题是"黑暗"。

静态上下文类型=主题上下文;

关于

nder() {
return <Button theme={this.context} />;
}
}
有时候,有些数据需要被很多组件访问,而且这些组件在组件树的不同层上。Context可以使我们以“广播”的形式,在各个组件中共享数据的改变
Context相关API
React.createContext
const MyContext = React.createContext(defaultValue);复制代码
创建一个新的Context对象。当React渲染一个组件,且该组件注册了Context时,它将读取父组件中,距离该组件最近的Provider组件的Context值
defaultValue只有在“Consumer”组件找不到Provider组件时,才会被使用。
Context.Provider
<MyContext.Provider value={/ some value /}>复制代码
每个Context对象都携带一个名叫Provider的React组件。Provider可以使得“Consumer”组件监听context的变更
通过向Provider的后代Consumer组件传递value的prop,一个Provider可以与多个Consumer组件建立联系。
所有的后代Consumer组件在Provider的value属性更新后,都会被重新渲染。这个更新从Provider到其后代Consumer组件之间传播,但是并不会触发shouldComponentUpdate方法。所以即使Consumer组件的祖先组件没有更新,Consumer组件也会更新
Context使用与Object.is相同的算法来对比value的新、旧值,以判定其value是否被更新了
注意
当向value传递对象时,这种判定value是否改变的方式可能会引起问题。
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/ perform a side-effect at mount using the value of MyContext /
}
componentDidUpdate() {
let value = this.context;
/ ... /
}
componentWillUnmount() {
let value = this.context;
/ ... /
}
render() {
let value = this.context;
/ render something based on the value of MyContext /
}
}
MyClass.contextType = MyContext;
为class的contextTpe属性赋值一个Context对象后,我们可以通过this.context在组件的各个声明周期函数中获取到当前的Context对象的方法
注意:
通过这种方式,每个组件只能注册一个context对象。如果需要读取多个context的value值
如果编码中使用了ES实验中的语法,那么可以使用类的静态(static)成员来初始化contextTYpe.代码如下:
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/ render something based on the value /
}
}
Context.Consumer
<MyContext.Consumer>
{value => / render something based on the context value /}
</MyContext.Consumer>
Consumer是一个监听context变化的React组件。它使得我们可以在一个函数组件中,监听contxt的改变。
Consumer组件要求其子元素为一个函数。该函数的参数接收当前的context的value值,要求返回一个React节点(node) 传递给该函数的参数value等于距离此Consumner最近的外层Provider组件的context值。如果没有外层的Provider组件,则等于调用createContext()时传递的参数值(context的默认值)。
注意
更多关于“子元素为一个函数”的信息
栗子
在嵌套组件中更新Context
开发中,我们经常需要在某些嵌套结构很深的组件上更新context的value值。此时,我们可以向下传递一个函数,用它来更新context的value。代码如下:
theme-context.js
// Make sure the shape of the default value passed to// createContext matches the shape that the consumers expect!export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}

export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context';import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);

this.toggleTheme = () => {
  this.setState(state => ({
    theme:
      state.theme === themes.dark
        ? themes.light
        : themes.dark,
  }));
};
// State also contains the updater function so it will
// be passed down into the context provider
this.state = {
  theme: themes.light,
  toggleTheme: this.toggleTheme,
};

}

render() {
// The entire state is passed to the provider
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}

function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}

ReactDOM.render(<App />, document.root);
使用多个Contexts
为了保持React的快速渲染,我们需要将每个consumer组件编写成一个独立的组件节点(node)
// Theme context, default to light themeconst ThemeContext = React.createContext('light');
// Signed-in user contextconst UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;

// App component that provides initial context values
return (
  <ThemeContext.Provider value={theme}>
    <UserContext.Provider value={signedInUser}>
      <Layout />
    </UserContext.Provider>
  </ThemeContext.Provider>
);

}
}

function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}

// A component may consume multiple contexts
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
如果有两个以上的context经常一起使用,我们需要考虑创建一个render prop component一并提供两个Context
注意
因为context使用引用标示符(reference identity)来判断何时需要重新渲染,所以有些情况下,当provider的父元素重新渲染时,会触发consumer的非内部渲染。例如下面代码,在每次Provider重新渲染时,会重新渲染所有的consumer组件。因为会一直创建一个新的对象赋值给value(value一直在变)
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
);
}
}
为了避免这个问题,可以将value放在组件的state中
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}

render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}

感谢各位的阅读!关于“Context-React如何跨组件访问数据”这篇文章就分享到这里了,希望

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/132515.html

(0)

相关推荐

  • 微信小程序怎么嵌入python代码(python如何编写微信小程序)

    技术python如何实现微信小程序反编译这篇文章主要介绍“python如何实现微信小程序反编译”,在日常操作中,相信很多人在python如何实现微信小程序反编译问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法

    攻略 2021年12月13日
  • Java基础——面向对象2

    技术Java基础——面向对象2 Java基础——面向对象2Java基础——面向对象2
    继承
    子类无法使用父类的私有属性或方法
    Java中只有单继承,没有多继承
    Ctrl + h 打开继承树
    在Java中

    礼包 2021年12月15日
  • 泰山海拔高度,泰山的主峰到底有多高啊

    技术泰山海拔高度,泰山的主峰到底有多高啊泰山的主峰是玉皇顶泰山海拔高度,高度海拔1532.7米。玉皇顶,是泰山主峰之巅,因峰顶有玉皇庙而得名。玉皇顶旧称太平顶,又名天柱峰,始建年代无考,明成化年间重修。神龛上匾额题“柴望

    生活 2021年10月22日
  • 方法介绍:回归,regression)

    技术方法介绍:回归,regression) 方法介绍:回归(regression)回归可用于做实证研究,研究自变量和因变量之间的内在联系和规律,常见于社会科学研究中。回归也可用来做预测,根据已知的信息去

    礼包 2021年11月10日
  • 傅雷家书1954年概括,傅雷家书1954年的主要内容

    技术傅雷家书1954年概括,傅雷家书1954年的主要内容1954年,傅聪出国学习钢琴,孤身远在他乡,孤独枯寂,傅雷夫妇以家书来鼓励儿子潜心学习,报效国家.多年来,傅雷夫妇的家书一直伴随着傅聪的生活,学习,乃至恋爱,结婚生

    生活 2021年10月27日
  • docker中Dockerfile如何自定义mycentos

    技术docker中Dockerfile如何自定义mycentos这篇文章主要为大家展示了“docker中Dockerfile如何自定义mycentos”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大

    攻略 2021年11月15日