本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-05-26
class ChildInput extends Component {
render(){
let pInput = this.props.parentIpt //2.2子组件接受父组件暴露的元素
return (
<input type="text" ref={el=>this.props.getChildInput(el)} />
// 1.2子组件通过el传值给props接受到的函数 将input暴露给父组件 ref中函数的形参就是本身元素的指针el
)
}
}
class ParentInput extends Component {
render(){
// 1.1通过传递一个赋值接受ref的函数给子组件
return (
<div>
<input type="text" value="2.1 父组件把自己的dom元素暴露给子组件" ref={el=>this.myInput = el}/>
<ChildInput
getChildInput={this.getChildInput.bind(this)}
parentIpt = {this.myInput}
ref={ el => this.chilidComp = el}
>
</ChildInput>
<button onClick={this.setFocus.bind(this)}>点击让子组件的input聚焦</button>
</div>
)
// 3. 可以暴露这个组件给父组件 像上面的ref={el=>this.chilidComp=el}一样 但是不介意使用
// 因为这样 父组件中的chilidComp这个变量代表了整个子组件 会占用很大的空间 性能不好
}
getChildInput(el){
// 1.3子组件执行render的时候 就会触发传过去的getChildInput函数 把el作为参数传到父组件
// 这样父组件就取到了子组件暴露的dom元素 然后赋值给自己的变量
this.cInput = el;
}
setFocus(){
this.cInput.focus()
}
}
子组件中可以使用this.props.children
拿到父组件传入的插槽:
使用代码如下:
class Child extends Component {
render(){
return (
<div>
{this.props.children} ---将整个分发的内容放在这里
</div>
)
}
}
class Parent extends Component {
render(){
return (
<div>
<Child>
<p>父组件中的p元素</p>
<span>父组件中的span元素</span>
</Child>
</div>
)
}
}
// 或者传一个虚拟dom对象给子组件 做分发
class Child extends Component {
render(){
return (
<div>子组件的div
{this.props.headDom} --- 展示父组件给的h1
</div>
)
}
}
class Parent extends Component {
render(){
return (
<div>
<Child headDom={<h1> 给你一个h1去展示吧 </h1>}></Child>
</div>
)
}
}
class Child extends Component {
render(){
return (
<div>
<h4>放上面的插槽</h4>
{
// 可以放在外面判断,这里写只是更直接的表达意思而已
// 如果只设置了一个插槽 还要处理对象为这样 [this.props.children]
this.props.children && Array.isArray(this.props.children)
? this.props.children.filter(item => item.ref === 'top')[0]
: ''
}
<hr/>
<h4>放下面的插槽</h4>
{
this.props.children && Array.isArray(this.props.children)
? this.props.children.filter(item => item.ref === 'bottom')[0]
: ''
}
</div>
)
}
}
class Parent extends Component {
render(){
return (
<div>
<Child>
<div ref="top">我是上面的插槽</div>
<div ref="bottom">我是下面的插槽</div>
</Child>
</div>
)
}
}
// 有三个组件 A 包含 B ,B包含 C
// 如果A组件想传值给C组件 要使用props传给B 再传给C
// 这种传值 可以使用 Provider&Consumer 来简化
const ValContext = React.createContext('默认值')
// 或者
const { Provider, Consumer } = React.createContext('默认值')
// 这样下面 就可以使用Provider Consumer 来充当根元素 而不是 ValContext.Provider
// 提供数据的组件ValContext.Provider 供应者
// 需要接受数据的组件的根元素 使用ValContext.Consumer 消费者
class Ccom extends Component {
render() {
return (
<ValContext.Consumer>
展示从A传下来的值 函数中的参数value就是传来的值
函数返回一个虚拟dom元素 就可以展示传来的值在该组件上了
{value => <p>我接受到A传来的值 : {value} </p>}
</ValContext.Consumer>
)
}
}
class Bcom extends Component {
render() {
return (
<Ccom></Ccom>
)
}
}
class Acom extends Component {
render() {
return (
<ValContext.Provider value="我要传给c的值">
<Bcom></Bcom>
</ValContext.Provider>
)
}
}
看起来就是一个空标签,类似vue中的template充当根标签 但是不增加额外节点
render() {
return (
<>
<ChildA/>
<ChildB/>
</>
)
}
// 或者 因为空标签语法不接受 key 如果你要遍历的话 就会报警告
// React.Fragment 能够接收key 也是唯一只能接受key
render(){
return (
{
this.list.map(item=>(
<React.Fragment key={item.id}>
<ChildA/>
<ChildB/>
</React.Fragment>
))
}
)
}
比如一个有遮罩的模态框,必然需要添加在body上。
const bodyEl = document.getElementsByTags('body')[0]
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
bodyEl.appendChild(this.el);
}
componentWillUnmount() {
bodyEl.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
this.props.children, // 下面的Modal中的Child
this.el,
);
}
}
// 将模态框使用在父组件中 此时的Modal组件相当于一个中转 使用Portal则挂载在父组件上但可以不受父组件根元素div的限制
// 然后再modal中将child(即模态框的实际内容)添加在创建的div上 再将div(模态框)添加到body上
class Parent extends React.Component {
render() {
return (
<div>
<Modal>
<Child />
</Modal>
</div>
);
}
}
function Child() { // 无状态组件
return (
<div className="modal">
<button>Click</button>
</div>
);
}
高阶组件就是一个函数,且该函数接受一个组件作为参数,然后返回一个新的组件。相当于是一个工厂用来增强组件的,a,b组件都需要一把锤子,就将其传值给锤子工厂(高阶组件)去给a,b组件装一把锤子,这里的锤子就是公共部分,a,b都需要用到的。
高阶组件的参数:需要混入公共功能的组件
高阶组件的返回:已经增强过的组件
class Acom extends React.Component {
render() {
return (
<div>
<p>我是a,我需要一把{this.props.wuqi}</p>
<button onClick={this.props.show}>展示锤子吧!!!</button>
</div>
);
}
}
class Bcom extends React.Component {
render() {
return (
<div>
<p>我是b,我也需要一把{this.props.wuqi}</p>
<button onClick={this.props.show}>展示锤子吧!!!</button>
</div>
);
}
}
function myHighCom(Com){
// 匿名类 相当于匿名函数
return class extends React.Component {
constrcutor(props){
super(props)
this.state = {
wuqi: "锤子"
}
}
render() {
return <Com wuqi={this.state.wuqi} show={this.show}></Com>
}
show() {
console.log('展示我的锤子')
}
componentDidMount(){
console.log('我们在生命周期钩子函数里面也要做同样的事情')
}
}
}
const AplusCom = myHighCom(Acom)
const BplusCom = myHighCom(Bcom)
// 使用增强过的组件
class Parent extends React.Component {
render() {
return (
<div>
<AplusCom/>
<hr/>
<BplusCom/>
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById('app'))