文章目录
-
- React父子组件通信
-
- 认识组件嵌套
- 组件通信
-
- 父传子
- 参数验证
- 子传父
React父子组件通信
认识组件嵌套
组件之间存在嵌套关系:
在之前的案例中,我们只是创建了一个组件App;
如果我们一个应用程序将所有的逻辑都放在一个组件中,那么这个组件就会变成非常的臃肿和难以维护;
所以组件化的核心思想应该是对组件进行拆分,拆分成一个个小的组件;
再将这些组件组合嵌套在一起,最终形成我们的应用程序;
上面的嵌套逻辑如下,它们存在如下关系:
App组件是Header、Main、Footer组件的父组件;
import React, { Component } from 'react'
import Header from './Header'
import Main from "./Main"
import Footer from './Footer'
export class App extends Component {
render() {
return (
<div>
<Header/>
<Main/>
<Footer/>
</div>
)
}
}
export default App
Main组件是Banner、ProductList组件的父组件
import React, { Component } from 'react'
import Banner from './Banner'
import ProductList from './ProductList'
export class Main extends Component {
render() {
return (
<div>
<div>Main</div>
<Banner/>
<ProductList/>
</div>
)
}
}
export default Main
组件通信
在开发过程中,我们会经常遇到需要组件之间相互进行通信:
比如App可能使用了多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示;
又比如我们在Main中一次性请求了Banner数据和ProductList数据,那么就需要传递给他们来进行展示;
也可能是子组件中发生了事件,需要由父组件来完成某些操作,那就需要子组件向父组件传递事件;
总之,在一个React项目中,组件之间的通信是非常重要的环节;
父传子
父组件在展示子组件时,可能会传递一些数据给子组件:
父组件通过
属性=值
的形式来传递给子组件数据;子组件通过
this.props
获取父组件传递过来的数据;
例如我们来看这样一个需求, 父组件将定义的数组books传递给子组件, 由子组件进行展示
将数组传递给子组件
export class App extends Component {
constructor() {
super()
this.state = {
books: [
{name: "算法导论", price: 79},
{name: "数据结构", price: 69},
{name: "漫画算法", price: 59},
]
}
}
render() {
const { books } = this.state
return (
<div>
{/* 将数据传递给子组件 */}
<Header books={books}/>
</div>
)
}
}
在子组件接受父组件传递的数据
export class Header extends Component {
render() {
// 接受父组件传递过来的参数
const { books } = this.props
return (
<div>
<ul>
{
books.map(item => {
return (
<li key={item.name}>
名称: {item.name} 价格: {item.price}
</li>
)
})
}
</ul>
</div>
)
}
}
参数验证
对于传递给子组件的数据,有时候我们可能希望进行验证,特别是对于大型项目来说:
当然,如果你项目中默认继承了Flow或者TypeScript,那么直接就可以进行类型验证;
但是,即使我们没有使用Flow或者TypeScript,也可以通过
prop-types
库来进行参数验证;
从 React v15.5 开始,React.PropTypes 已移入另一个包中:prop-types 库
使用方法, 先在子组件中导入
PropTypes
, 再对传递过来的元素添加类型限制即可
import React, { Component } from 'react'
// 导入PropTypes
import PropTypes from 'prop-types'
export class Header extends Component {
render() {
const { books, name, age } = this.props
return (
<div>
<div>名字: {name} 年龄: {age}</div>
<ul>
{
books.map(item => {
return (
<li key={item.name}>
名称: {item.name} 价格: {item.price}
</li>
)
})
}
</ul>
</div>
)
}
}
// 对参数添加类型的限制
Header.propTypes = {
// 表示传入的类型是要求一个数组, 并且必传
books: PropTypes.array.isRequired,
// 传入类型string, 非必传
name: PropTypes.string,
// 传入类型number, 非必传
age: PropTypes.number
}
export default Header
更多的验证方式,可以参考官网:https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
比如验证数组,并且数组中包含哪些元素;
比如验证对象,并且对象中包含哪些key以及value是什么类型;
比如某个原生是必须的,使用 requiredFunc: PropTypes.func.isRequired
如果没有传递,我们希望有默认值呢?
我们使用defaultProps就可以了
Header.defaultProps = {
name: "默认名称"
}
子传父
某些情况,我们也需要子组件向父组件传递消息:
在vue中是通过自定义事件来完成的;
在React中同样是通过props传递消息,只是让父组件给子组件传递一个回调函数,在子组件中调用这个函数即可;
我们这里来完成一个案例:
将计数器案例进行拆解;
将按钮封装到子组件中:CounterButton;
CounterButton发生点击事件,将内容传递到父组件中,修改counter的值;
演示代码
父组件传递一个事件给子组件CounterButton
import React, { Component } from 'react'
import ConterButton from './c-cpn/ConterButton'
export class App extends Component {
constructor() {
super()
this.state = {
conter: 100
}
}
changeConter(conter) {
this.setState({ conter: this.state.conter + conter })
}
render() {
const { conter } = this.state
return (
<div>
<h2>{conter}</h2>
{/* 向子组件中传入一个事件 */}
<ConterButton getConter={conter => this.changeConter(conter)}/>
</div>
)
}
}
export default App
子组件在按钮发生点击时, 对父组件的传递的函数进行回调, 并传入一个参数出去
import React, { Component } from 'react'
export class ConterButton extends Component {
btnClick(conter) {
// 当按钮发生点击事件时, 对父组件传递过来的函数进行回调
this.props.getConter(conter)
}
render() {
return (
<div>
<button onClick={() => this.btnClick(-1)}>-1</button>
<button onClick={() => this.btnClick(1)}>+1</button>
</div>
)
}
}
export default ConterButton