1、context 状态树传参
1.1、解释
Context 旨在共享一个组件树,可被视为 “全局” 的数据,达到越级传递,
场景:当前经过身份验证的用户,主题或首选语言,包括管理当前的 locale,theme,或者一些缓存数据。
-
createContext():
用于创建context对象(上下文),需要一个defaultValue的参数,并返回一个包含Provider(提供者),以及Consumer(消费者)的对象。
-
Provider:
提供者,提供数据。接收一个将要被往下层层传递的props,该值需在组件树最顶层设置。一个Provider可以关联到多个Consumers。这是一个顶层用于提供context的组件,包含一个value的props,value是实际的context数据。
-
Consumer:
消费者,使用者,接收一个函数作为子节点,函数接收当前 context 的值。这是一个底层用于获取context的组件,需要一个函数作为其子元素,该函数包含一个value的参数,这个参数就是上层所传递context value
创建一个context组件,并设定默认值:
const {Provider,Consumer} = React.createContext(defaultValue);
1.2、从父朝子传值(外朝内)
示例代码:
// context组件: 项目根目录下新建utils/myContext;
import {createContext} from "react";
export const {Provider, Consumer} = createContext({
name:"张三疯"
});
//顶层组件:./src/App.js
import {Provider} from "./utils/myContext"
function App() {
let val={
name:"hi"
};
return (
<div className="App">
<Provider value={val}>
<Home />
</Provider>
</div>
);
}
//孙子组件: 在Home组件及子孙组件都可获取值
import {Consumer} from "../utils/myContext";
export default class GoodsList extends React.Component {
render = () => (
<div className="goodsList-box">
<h1>商品列表:</h1>
<Consumer>
{
(val) => <div> { val.name } </div>
}
</Consumer>
</div>
)
}
注意:
export const {Provider, Consumer} = createContext({
name:"晓晓"
});
这个默认值是在顶层组件没有使用Provider组件时的值
,而不是,没有给value属性赋值时的值。
也就是说:当顶层组件的代码如下时,默认值为
'晓晓
’:
function App() {
let val={
name:"hi"
};
return (
<div className="App">
<Home />
</div>
);
}
1.3、在子组件改变状态树的数据
//根组件:
import {Provider} from "./utils/myContext"
export default class App extends React.Component {
constructor(props){
super(props);
this.state={
name:"宋晨",
setName:this.fn
}
}
fn=(str)=>{
this.setState({
name:str
});
}
render = () => (
<div className="App">
<Provider value={this.state} >
<Home />
</Provider>
</div>
)
}
//子组件里:
import {Consumer} from "../../utils/myContext";
export default class Banner extends Component {
render = () => (
<div className="box" >
<Consumer>
{
(obj)=>(
<div>
<p>姓名:{obj.name}</p>
<input type="button" value="修改" onClick={()=>obj.setName("hiwww")} />
</div>
)
}
</Consumer>
</div>
)
}
2、高阶组件(HOC)的构建与应用
高阶组件(HOC)是react中对组件逻辑进行重用的高级技术。但高阶组件本身并不是React API。它只是一种模式,这种模式是由react自身的组合性质必然产生的。
简单来说,高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件,高阶组件会对传入的组件做一些通用的处理。比如:我们希望给组件的的下方增加一个版权信息,那么就可以使用高阶组件。把原始组件传入,然后,给组件增加一个版权信息后,再返回。
高阶组件是通过将原组件 包裹(wrapping) 在容器组件(container component)里面的方式来组合(composes) 使用原组件。高阶组件就是一个没有副作用的纯函数。
如:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
高阶函数是:higherOrderComponent
传入的组件是:WrappedComponent
返回的组件是:EnhancedComponent
示例代码:
// 带上版权的高阶函数
function withCopyRight(OldCom){
class NewCom extends React.Component{
render() {
return (
<div>
<OldCom />
<hr/>
<div>
Copyright © 2020 Sohu All Rights Reserved. 版权所有
</div>
</div>
);
}
}
return NewCom;
}
//原始组件
class CommentList extends React.Component {
render() {
return (
<div>
今天天气不错
</div>
);
}
}
//调用高阶函数后的组件
const CommentListWithCopyRight = withCopyRight(CommentList);
ReactDOM.render( <div> <CommentListWithCopyRight /></div> ,$("box"));
function $(id){
return document.getElementById(id);
}
注意(重要):
1、不要在render函数里使用高阶组件
2、必须将静态(static)方法做拷贝
当使用高阶组件包装组件,原始组件被容器组件包裹,也就意味着新组件会丢失原始组件的所有静态方法,解决这个问题的方法就是,将原始组件的所有静态方法全部拷贝给新组件。
3、Refs不能传递
一般来说,高阶组件可以传递所有的props属性给包裹的组件,但是不能传递refs引用。
4、不要在高阶组件内部修改(或以其它方式修改)原组件的原型属性(prototype)。
5、约定:将不相关的props属性传递给包裹组件
6、约定:最大化使用组合
7、约定:包装显示名字以便于调试