嵌套逐级传递props的场景&refs
- 嵌套逐级传递props的场景
以组件为单元开发的react和vue都存在嵌套逐级传递props的场景。但它们在简化这种复杂场景的方法有不同。 - refs
react与vue都有引用的概念,其用法有不同。
react
- 嵌套逐级传递props的场景
react解决嵌套逐级传递props的场景采用最外层创建context的方法结合发布订阅的设计模式。
所有包含在发布者(provider)内的订阅者(consumer)在发布的数据源变化时,都能够重新渲染ui界面。
从创建context到使用context数据。涉及到四个api,分别是:React.createContext、、MyContext.Provider、MyContext.Consumer、MyContext.displayName。具体看以下demo。
// src\ctx-refs\ctx.js
import React from "react";
// 只有在未提供Provider时,默认值才会生效
// 此处可以注释掉MyContext.Provider尝试默认值
const MyContext = React.createContext(2);
// 类似于vue选项name,此处也要给Context一个名字以区分调试
MyContext.displayName = "Count";
class Son extends React.Component{
static contextType = MyContext;
render(){
// 生命周期rende函数ctx指向的数据能够相应变化
console.log(this.context)
return(<MyContext.Consumer>
{value => <span>{ value }</span>}
</MyContext.Consumer>)
}
}
function Father(props) {
return(<div>{props.children}</div>)
}
function Home() {
return(<Father><Son/></Father>)
}
export default class Demo extends React.Component{
state = {
value: 1
}
render() {
let { value } = this.state
return(<div>
<button onClick={()=>{this.setState({value: ++value})}}>改变最上层ctx数据</button>
<MyContext.Provider value = {value}>
<Home/>
</MyContext.Provider>
</div>)
}
}
图1-1为Context在react-devtooll展示名:
- refs
react中的ref通过api创建,然后绑定到对应组件或dom上,多层组件还有传递ref这一说。详细请看以下demo。
import React from "react";
class Son extends React.Component {
state = {
age:1
}
grow = () => {
let { age } = this.state;
this.setState({age: ++age})
}
render(){
const { age } = this.state;
const { forwardedRef } = this.props;
return(
<>
<div>Son, age: { age }</div>
<GrandSon ref = {forwardedRef} />
</>
)
}
}
class GrandSon extends Son {
render(){
const { age } = this.state;
return(
<div>GrandSon, age: { age }</div>
)
}
}
const refSon = React.createRef();
const refGrandSon = React.createRef();
export default class Father extends React.Component {
render(){
return(<div>
<button onClick = {() => {refSon.current.grow()}}>养育儿子</button>
<button onClick = {() => {refGrandSon.current.grow()}}>养育孙子</button>
{/* ref为绑定ref, forwardedRef为传递给子组件ref */}
<Son ref = {refSon} forwardedRef = {refGrandSon}></Son>
</div>)
}
}
Vue
- 嵌套逐级传递props的场景
render函数写法可以避免出现逐级传递props,因为所有的createElement都能直接访问顶层组件的作用域,也就是tempalte里面无限组件插槽嵌套。想想就觉得恐怖。如下面的写法,实际上我也只是在GrandSon上直接访问顶层组件传递了一次props,没有经过Son。
//函数式组件、render写法
import Vue from "vue";
let _c = Vue.extend.bind(Vue);
const Son = _c({
render(h){
return h("div", ["儿子", this.$slots.default])
}
});
const GrandSon = _c({
render(h){
return h("div", ["孙子", this.customProps])
},
props:["customProps"]
});
const Container = _c({
// functional: true,
// render(h,ctx){
// return h(Son, ctx.data, [h(GrandSon, ctx.data)])
// }
// or
render(h){
return h(Son, {nativeOn:{click:()=>{++this.customProps}}},[h(GrandSon,{props:{customProps:this.customProps}})])
},
data(){
return{
customProps:1
}
}
})
export default Container
vue还可以通过$attrs传递中间组件未接受使用的属性到更深的组件:
<template>
<div>
<Son v-bind="$attrs" />
</div>
</template>
<script>
import Vue from "vue";
Vue.component("Son",{
render(h) {
return h("div",["子组件"])
},
mounted(){
console.log(this.customProps)
console.log(this.$attrs)
},
props:["customProps"]
})
export default {
data(){
return{}
}
}
</script>
- refs
vue的ref就很简单了
<template>
<div>
<Son ref="son" />
</div>
</template>
<script>
mounted(){
// 内部子组件不用通过父组件为其转发ref。直接通过逐级访问ref就能访问到内部组件的引用。
console.log(this.$refs["son"])
}
</script>