1. Context简介
Context提供了一个无需为每层组件手动添加Props,就能在组件树间进行数据传递的方法。
- 若有一个值,在父组件定义过,想要在孙子组件中使用,使用props形式就需要将该值从父组件传给子组件,再从子组件传给孙组件,若层级更深则传起来十分复杂和麻烦。
- Context提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树逐层传递props。
2. Context使用
使用场景: 我想要在App.js页面中注入某些内容,然后自定义一个水印组件。水印组件中的内容就是我在App.js中想要全局展示的固定内容。
2.1 定义context.js const MyContext = React.createContext(defaultValue);
- utils/context.js
- 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
- 只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。此默认值有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。
import React from "react";
let { Provider, Consumer } = React.createContext()
export {
Provider,
Consumer
}
2.2 Provider
- App.js 注入值
- 每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
- Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
- 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。从 Provider 到其内部 consumer 组件(包括 .contextType 和 useContext)的传播不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件跳过更新的情况下也能更新。
import { Provider } from './utils/context';
function App() {
let userInfo ={
name: 'Ably',
age: 25,
phone: 188******31,
email: '**********@163.com'
}
return (
<Provider value={{sendItem: userInfo}}>
<div>
...
</div>
</Provider>
);
}
export default App;
2.3 Consumer
- 一个 React 组件可以订阅 context 的变更,此组件可以让你在函数式组件中可以订阅 context。
- 这种方法需要一个函数作为子元素(function as a child)。这个函数接收当前的 context 值,并返回一个 React 节点。传递给函数的 value 值等价于组件树上方离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext() 的 defaultValue。
- 想要给Myarticle页面组件增加水印组件Watermark
- Myarticle/index.js 页面中使用水印组件
import Watermark from '../../components/Watermark'
render() {
return (
<div className='article_container'>
<Watermark /> // 水印组件
<Suspense fallback={<Loading text="加载中..." />}>
<ArticleList list={this.state.list} />
</Suspense>
</div>
)
}
- 水印组件,使用Consumer接收Provider提供的值
- Watermark/index.js
import { Component } from 'react';
import { Consumer } from '../../utils/context';
import './index.scss'
export default class Watermark extends Component {
render() {
return (
<div>
<Consumer>
{
({sendItem}) => {
return (
<div className='watermark'>
<span className='mr_8'>
{sendItem.name}
</span>
<span>
{sendItem.email}
</span>
</div>
)
}
}
</Consumer>
</div>
)
}
}
- Watermark/index.css
.watermark {
transform: rotate(45deg);
position: fixed; // 使用fixed固定定位,只要展示固定的值,那么之后这个无论页面如何滑动,都能保证下面的水印不被更改
width: 100%;
height: 100%;
color: rgb(247, 243, 243);
font-size: 44px;
text-align: center;
line-height: 100%;
padding-top: 160px;
z-index: -1;
}
.mr_8 {
margin-right: 8px;
}
2.4 水印效果图
根据以上定义后,展示的水印效果如下
2.5 多方位水印
只有固定某个位置有水印,一旦页面中的其他内容需要保密打水印时,容易产生遗漏情况,我们可以将满屏大多数位置上增加自己的水印
2.5.1 实现思路
- 若想满屏展示,那必然会是有一个大的list,横向铺满屏幕,大的list里面每一个小list纵向分布,铺满纵向
- 外面大list,flex,横向均分
- 里面小的list,纵向展示,铺满整个纵向屏幕
- 此时页面内容已经铺满,然后将每一个小list里面的每一个item旋转
2.5.2 代码实现
- watermark.js
import { Component } from 'react';
import { Consumer } from '../../utils/context';
import './index.scss'
export default class Watermark extends Component {
render() {
let arrLenth = 6
const list = Array.from({length: arrLenth})
return (
<div>
<Consumer>
{
({sendItem}) => {
return (
<ul className='watermark'>
{
list.map((item, parentIndex) => {
return <ul className='watermark_column' key={parentIndex}>
{
list.map((item, index) => {
return <li key={index} className='watermark_column_item'>
<span className='mr_8'>
Ably
{/* {sendItem.name} */}
</span>
<span>
********131
{/* {sendItem.email} */}
</span>
</li>
})
}
</ul>
})
}
</ul>
)
}
}
</Consumer>
</div>
)
}
}
- watermark.css
.watermark {
position: fixed;
width: 100vw;
height: 100vh;
color: rgb(247, 243, 243);
font-size: 22px;
line-height: 100%;
z-index: -1;
display: flex;
justify-content: space-between;
align-items: stretch;
top: 0;
left: 0;
}
.watermark_column {
display: flex;
flex-direction: column;
justify-content: space-around;
}
.watermark_column_item {
transform: rotate(45deg);
}
.mr_8 {
margin-right: 8px;
}
2.5.3 效果图
如果有用,点个赞呗~
总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~