什么是组件化开发?组件化开发的思想
如果现在需要我们开发一个大型的页面,如果我们将所有的处理逻辑放在一起,那么这个页面的逻辑就会变得极为复杂且不利于后续管理。但是如果我们把一个界面 拆分 成一个个小的模块和功能。每个功能块完成属于自己独立的功能,那么之后整个页面的管理和维护就变得非常容易了。
所以,我们在进行React或Vue开发的时候要使用组件化的思想
优势
- 将一个页面拆分为多个组件,方便管理和维护
- 组件可以复用
- 每个组件都有对应的逻辑和其功能
React的组件和Vue的组件
React的组件和Vue的组件相比更加灵活,按照不同的方式可以分成很多类组件,例如:
- 根据组件的定义方式:函数组件和类组件
- 根据组件内是否有状态需要维护:无状态组件和有状态组件
- 根据不同的职责:展示型组件和容器型组件
类组件
类组件的定义需满足如下要求:
- 组件的名称大写字符开头
- 类组件需要继承来自React.Component
- 必须实现render函数
函数式组件
函数式组件有如下特点:
- 没有this对象
- 没有内部状态
- 没有生命周期
组件的通信
无论是Vue还是React,在组件化开发过程中也需要相互进行数据的传递,最基本:父组件给子组件传递数据,那么React是如何实现这个的呢。
父组件向子组件传递数据使用的是props,详细看如下例子:
//父组件
//..
class Father extends React.Component {
render(){
return (
<Childcpn name="fengan" age="18" height="185cm" />
<Childcpn2 name="fengan" age="18" height="185cm" />
)
}
}
//类组件演示代码 - 子组件
class Childcpn extends React.Component {
render(){
let { name,age,height } = this.props
return (
<div> { name+age+height } </div>
)
}
}
//函数组件演示代码 - 子组件
function Childcpn2(props) {
const {name,age,height} = props
render(){
return (
<div> { name+age+height } </div>
)
}
}
propTypes属性验证
在组件传值时候使用propTypes库对传入组件的值进行属性验证或设置属性的默认值:
如下代码对propTypes库的使用进行简单的指引:详细可参考React官网
//1.导入prop-types库
import PropTypes from 'prop-types'
//2.对子组件进行验证
//组件声明时的名字.属性
Childcpn.propTypes = {
name:PropTypes.string.isRequired,
age:PropTypes.number,
height:PropTypes.number,
names:PropTypes.array,
}
//除了可以验证还可以指定默认值
Childcpn.defaultProps = {
name:"fengan",
age:18,
height:1.85,
names:['aaa','bbb']
}
子组件传递数据给父组件
现在,我们知道了父组件如何传递数据给子组件,那么在我们开发的时候,时常也需要子组件传递数据给父组件。那么React如何实现的呢?
原来阿,React中同样是通过props来实现子组件传递消息给父组件的,只是父组件给子组件传递一个回调函数,在子组件中调用这个函数即可;详细看如下代码
如何使用prop传递函数:
//子传父通信
//子组件
class Btnclick extends Component {
render() {
let { addClick } = this.props
return <button onClick={ addClick }>+1</button>
}
}
//父组件
class App extends Component {
constructor(props) {
super(props)
this.state = {
count:0
}
}
render() {
let { count } = this.state
return (
<div>
<div>{ count }</div>
//使用子组件,并传递父组件的函数到子组件
<Btnclick addClick={ ()=>{ this.addClick() } } />
</div>
);
}
addClick() {
let { count } = this.state
count += 1
this.setState({
count
})
}
}
export default App;
案例:实现子传父
//父组件
import React, { Component } from 'react'
import TabControl from './TabControl'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
titles:['新款','精选','流行'],
currentTitle:'新款'
}
}
render() {
let { titles,currentTitle } = this.state
return (
<div>
<TabControl titles={ titles } itemClick={ (index) => { this.getTitle(index) } } />
<h2>{ currentTitle }</h2>
</div>
)
}
getTitle(index) {
let { titles,currentTitle } = this.state
currentTitle = titles[index]
this.setState({
currentTitle
})
}
}
//子组件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './style.css';
export default class TabControl extends Component {
constructor(props) {
super(props)
this.state = {
currentIndex:0
}
}
static propTypes = {
titles: PropTypes.array.isRequired,
itemClick: PropTypes.func.isRequired,
}
render() {
let { titles,itemClick } = this.props
let { currentIndex } = this.state
return (
<div>
<ul className="tab-control">
{ titles.map(
(item,index) =>
<li key={index}
className= { currentIndex === index ? 'active tab-item' : 'tab-item'}
onClick={ e => {
this.itemClick(index);
itemClick(index)
} }
>
{item}
</li>) }
</ul>
</div>
)
}
itemClick(index) {
this.setState({
currentIndex:index
})
}
}
//样式文件
.tab-control {
display: flex;
padding: 0;
margin: 0;
}
.tab-item {
flex: 1;
list-style: none;
text-align: center;
line-height: 44px;
height: 44px;
}
.tab-control .active {
border-bottom: 2px solid orange;
color: orange;
}
总结:
原来实现子传父的形式是:父组件使用props传递函数到子组件,子组件调用这个函数。在子组件中把需要传递数据放入到props接受到的函数参数中。那么父组件的这个函数的参数就是子组件参数过来的数据,之后在再函数中对子组件传递过来的数据实现相应的代码。
在React中实现Vue的插槽
这里需要先给大家补充一个知识点:
我们在使用子组件的时候可以使用双标签的书写方式,在双标签中写的内容,会自动的传递到子组件的props.children属性中
//父组件
class App extends Component {
render() {
return (
<div>
//双标签的形式使用子组件
<NavBar>
<a>aaa</a>
<span>bbb</span>
</NavBar>
</div>
)
}
}
//子组件
class NavBar extends Component {
render() {
return (<div>
<div>{this.props.children[0]}</div>
<div>{this.props.children[1]}</div>
</div>)
}
}
上述案例大多推荐只传递一个组件进去的时候使用,而如果需要传递多个组件,上述的方式有个弊端就是需要按照一定的顺序写标签。所以针对传多个插槽,我们提供另外一种方式:使用props传递属性,属性值为需要插入对应地方的标签。以达到具名插槽的作用。
跨组件通信Context
Context是React提供用于在组件之间共享此类值的方式的API,而不必显示式地通过组件树的逐层传递props。
详情可参考官网文档