@TOC
父子组件关系简谈
父组件 内 包含有 子组件,这是基本关系
所以,父组件render渲染时,子组件会紧紧跟随伴其渲染,无论何种情况都会(例如父组件自己setState,子组件也会跟着重新render)。
ref属性
下图是16.x以后React新的生命周期图,其实按使用频率来看没什么必要在意,我们平常也就用ComponentDidMount()多一些。这个函数会在一个组件渲染完成后“必定执行”,所以你想在组件渲染完后干些什么其他的操作可以在这里自由DIY。
不过关于生命周期这里有个重要的点需要注意:不要在ComponentDidMount()里面执行this.setState()函数!每次setState都会强制重新渲染组件,而重新渲染又必然重新执行一次ComponentDidMount(),禁止套娃!!!
了解如上基本情况后就可以上手写写代码了
父组件调用子组件函数
目标:在父组件里调用子组件的一个函数 我使用的方法:ref与onRef。因为实际上可以为多个孩子创建好关联,所以我一般都是使用这种方法的
下面我用react脚手架的App.js作为父组件进行演示
App.js
import React, { Component } from 'react'
import Child1 from './component/Child1'
export default class App extends Component {
// react的onRef会自动检查从哪个名字的组件进来执行的onRef
onRef (name, ref) {
switch (name) {
case 'Child1':
this.Child1 = ref
break
default:
break
}
}
// 调用子组件Child1的一个函数
// 其实子组件里那个函数随便起名,但为了做工程,代码命名统一一些,这里都叫func1
func1 = () => {
console.log("父组件调用child1")
this.Child1.func1()
}
// 关于如何、何时调用func1,自己具体项目具体分析,这里为了演示,就简单采用Button的onClick触发来展示一下
render() {
return (
<div>
<button onClick={this.func1}>
<Child1 onRef={this.onRef.bind(this)}/>
</button>
</div>
)
}
}
Child1.js
import React, { Component } from 'react'
export default class Child1 extends Component {
// 渲染后和父组件的ref: Child1建立关联,使父组件调用Child1时直接使用的就是子组件Child1对象
componentDidMount = () => {
this.props.onRef('Child1', this)
}
func1 = () => {
console.log("我雀实是Child1")
}
render() {
return (
<div>
我是Child1
</div>
)
}
}
点击按钮 1,效果如图:
父组件调用子组件函数且传参
目标:在父组件里调用子组件的一个函数,并且由父组件传参数给子组件函数(非props)
那么我接下来继续在上文的基础上增加一个child2:
App.js
import React, {Component} from 'react'
import Child1 from './component/Child1'
import Child2 from './component/Child2'
export default class App extends Component {
// react的onRef会自动检查从哪个名字的组件进来执行的onRef
onRef (name, ref) {
switch (name) {
case 'Child1':
this.Child1 = ref
break
case 'Child2':
this.Child2 = ref
break
default:
break
}
}
// 调用子组件Child1的一个函数
// 其实子组件里那个函数随便起名,但为了做工程,代码命名统一一些,这里都叫func1
func1 = () => {
console.log("父组件调用child1")
this.Child1.func1()
}
func2 = (param1, param2) => {
console.log("父组件调用child2")
this.Child2.func2(param1, param2)
}
// 关于如何、何时调用func1,func2,自己具体项目具体分析,这里为了演示,就简单采用Button的onClick触发来展示一下
render() {
return (
<div>
<button onClick={this.func1}>
<Child1 onRef={this.onRef.bind(this)}/>
</button><br/>
{/* 使用bind函数,绑定App对象后,附加上自己想传的各个参数 */}
<button onClick={this.func2.bind(this, "参数1", "参数2")}>
<Child2 onRef={this.onRef.bind(this)}/>
</button>
</div>
)
}
}
Child2.js
import React, { Component } from 'react'
export default class Child1 extends Component {
componentDidMount = () => {
this.props.onRef('Child2', this)
}
func2 = (param1, param2) => {
console.log("我真的是Child2",param1, param2)
}
render() {
return (
<div>
我是Child2
</div>
)
}
}
点击按钮 2,效果如图:
子组件调用父组件函数
目标:子组件调用父组件的一个函数
重要应用:子组件可通过这种形式向父组件传参
使用ref的话只能简单得让子组件“为父所用”,所以这里可以使用神奇的“props”参数,直接把一个函数传给子组件。这样,父组件定义的东西就相当于送给子组件使用了
App.js
import React, {Component} from 'react'
import Child1 from './component/Child1'
export default class App extends Component {
funcFather1 = () =>{
console.log("Child1调用本爹了")
}
// 关于如何、何时调用func1,func2,自己具体项目具体分析,这里为了演示,就简单采用Button的onClick触发来展示一下
render() {
return (
<div>
<Child1 funcFather1={this.funcFather1}/>
</div>
)
}
}
Child1.js
import React, { Component } from 'react'
export default class Child1 extends Component {
// 渲染后和父组件的ref: Child1建立关联,使父组件调用Child1时直接使用的就是子组件Child1对象
componentDidMount = () => {
this.props.onRef('Child1', this)
}
func1 = () => {
console.log("我雀实是Child1")
}
render() {
return (
<div>
我是Child1<br/>
<button onClick={this.props.funcFather1}>
Child1要调用他爹
</button>
</div>
)
}
}
点击div内按钮,效果如图:
子组件调用父组件函数且传参
在使用props后其实子组件向父组件传参就很简单了,直接传!
App.js
import React, {Component} from 'react'
import Child1 from './component/Child1'
import Child2 from './component/Child2'
export default class App extends Component {
funcFather1 = () =>{
console.log("Child1调用本爹了")
}
funcFather2 = (param1, param2) =>{
console.log("Child2调用本爹了", param1, param2)
}
// 关于如何、何时调用func1,func2,自己具体项目具体分析,这里为了演示,就简单采用Button的onClick触发来展示一下
render() {
return (
<div>
<Child1 funcFather1={this.funcFather1}/>
<Child2 funcFather2={this.funcFather2}/>
</div>
)
}
}
Child2.js
import React, { Component } from 'react'
export default class Child1 extends Component {
render() {
return (
<div>
我是Child2<br/>
<button onClick={this.props.funcFather2("欸嘿", "欸嘿囊带优")}>
Child2要调用他爹
</button>
</div>
)
}
}
点击div内按钮 2,效果如图:
歪日,,点击了一点用也没有,但渲染时却执行了
原因分析: 由于在Child2的button onClick属性中我们写的是.funcFather2()这种带括号形式,而非.funcFather2,渲染时这个函数成为了直接执行的一段代码,而非被作为onClick触发的函数
解决办法: 在Child2定义新函数用来实现触发
Child2.js(改进)
import React, { Component } from 'react'
export default class Child1 extends Component {
funcFather2 = () => {
// 调用参数内的funcFather2
this.props.funcFather2("欸嘿", "欸嘿囊带优")
}
render() {
return (
<div>
我是Child2<br/>
{/* 这一次调用的是child2对象自己的funcFather2 */}
<button onClick={this.funcFather2}>
Child2要调用他爹
</button>
</div>
)
}
}
点击div内按钮 2,效果如图:
歪日,,渲染时又默认执行了???
解决办法: 在Child2定义以箭头函数触发
Child2.js(最终版)
import React, { Component } from 'react'
export default class Child1 extends Component {
funcFather2 = (param1, param2) => {
// 调用参数内的funcFather2
this.props.funcFather2(param1, param2)
}
render() {
return (
<div>
我是Child2<br/>
{/* 这一次调用的是child2对象自己的funcFather2 */}
<button onClick={()=>this.funcFather2("欸嘿", "欸嘿囊带优")}>
Child2要调用他爹
</button>
</div>
)
}
}
点击div内按钮 2,终于正常了,效果如图:
Route子组件调用父组件函数
Router中,组件的关系虽然和普通的差不多但是调用方式有所不同。 我选择的方法是直接在Route内调用render,把父组件函数传给子组件
App.js
import React, {Component} from 'react'
import Child1 from './component/Child1'
import { Route } from 'react-router-dom';
export default class App extends Component {
funcFather1 = () =>{
console.log("Child1调用本爹了")
}
render() {
return (
<div>
father
<Route path="/child1/" render={()=><Child1 funcFather1={this.funcFather1}/>} ></Route>
</div>
)
}
}
Child1.js
import React, { Component } from 'react'
export default class Child1 extends Component {
render() {
return (
<div>
<button onClick={this.props.funcFather1}>
Child1要调用
</button>
</div>
)
}
}
在Child页面点击按钮,效果如图:
补充一下我的项目框架,组件全放在component里了