跨层级数据传输
context的使用
第一步创建context对象
const MyContext = React.createContext(); export default MyContext;
第二步使用provider传递数据
export default const Index = (props) => { const [data] = React.useState({}); return <MyContext.Provider value={data}> {prop.children} </MyContext.Provider> };
注意这里的data应该是Index组件的一个状态,避免因为每次Index刷新,data重新是生成,导致子组件也diff,详细解释。
- 子孙组件消费value
消费context的值有三种方式; - contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* 基于 MyContext 组件的值进行渲染 */
}
}
MyClass.contextType = MyContext;
注意:你只通过该 API 订阅单一 context。如果你想订阅多个,请使用Cunsumer。如果你正在使用实验性的 public class fields 语法,你可以使用static
这个类属性来初始化你的contextType
。
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* 基于这个值进行渲染工作 */
}
}
Cunsumer
<MyContext.Consumer> {value => /* 基于 context 值进行渲染*/} </MyContext.Consumer>
这种方法需要一个函数作为子元素(function as a child)。这个函数接收当前的 context 值,并返回一个 React 节点。传递给函数的
value
值等价于组件树上方离这个 context 最近的 Provider 提供的value
值。如果没有对应的 Provider,value
参数等同于传递给createContext()
的defaultValue
。- useContext
使用比较简单, 但是只能在hook语法中使用:
function ShowAn(){
//调用useContext,传入从MyContext获取的上下文对象。
const value = useContext(MyContext);
return(
<div>
the answer is {value}
</div>
)
更加细致的内容可以参照react官方给出的文档
发布订阅模式
这个就不老生常谈了,懂的都懂,简单点说就是在订阅阶段将数据压入到队列中,发布的时候在遍历下这个队列取出想要的结果进行操作;
这里想说的是,到编写发布订阅这个模式的代码是我们应该注意到的一个细节就是,与订阅成对出现的还有一个就是取消订阅
,只有写了取消订阅的程序才会在一定程度上得到优化。
我们可以再订阅阶段的函数中在push
阶段的函数中这样操作,
const subscribe = (data) => {
Array.push(data);
return () => {
Array = Array.filter(item => item !== data);
}
}
// 然后在订阅函数调用的地方这样写
const unsubscribe = subscribe(data);
当我们想要取消订阅的时候直接调用unsubscribe()
即可是不是很方便呢!仔细看一下是不是很像是hook语法中useEffect的使用方式。
另外再说一点
今天看到一个有意思的博客,主要说异步中断的问题,一开始在说jq的ajax、axios,以及fetch的超时问题,前面的都比较简单,ajax有.abort()
函数, axios本来就存在time
字段,fetch也是可以中断的,只需一个AbortController
对象获取signal,并将这个信号对象作为fetch的选项传入。
async function fetchWithTimeout(timeout, resoure, init = {}) {
const ac = new AbortController();
const signal = ac.signal;
const timer = setTimeout(() => {
console.log("It's timeout");
return ac.abort();
}, timeout);
try {
return await fetch(resoure, { ...init, signal });
} finally {
clearTimeout(timer);
}
}
重点来了(敲黑板画知识点),万物皆可超时,Axios 和 fetch 都提供了中断异步操作的途径,但对于一个不具备 abort 能力的普通 Promise 来说,该怎么办?
文中给了一个很巧妙的解决办法;
Promise虽然没有abort能力但是我们想要对其进行超时中断可以利用.race方法,race 是竞速的意思,所以 Promise.race() 的行为是不是很好理解?
function waitWithTimeout(promise, timeout, timeoutMessage = "timeout") {
let timer;
const timeoutPromise = new Promise((_, reject) => {
timer = setTimeout(() => reject(timeoutMessage), timeout);
});
return Promise.race([timeoutPromise, promise])
.finally(() => clearTimeout(timer)); // 别忘了清 timer
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。