组件化开发
把页面逻辑拆分成一个一个小的组件,然后整合成一个大的页面,形成一个大的组件树,每一个组件都是一个小的模块。 对于一些重复使用的逻辑我们也可以拆分成组件,减少代码量
react的组件化划分
- 函数式组件 Functional Component
- 类组件 Class Comoonent
- 无状态组件(Stateless Component)和有状态组件(Stateful Component)
- 展示型组件 (Persenration Component)和容器型组件(Container Component)
一般情况下函数式组件是无状态组件,类组件认为是有状态组件
类组件要求
- 名称必须大写开头
- 需要继承React.Component
- 必须实现render函数
代码
import React from "react";
class App extends React.Component {
constructor (){
super() // 因为有继承得调用super()
this.state ={
title:"hello world"
}
}
render() {
const {title} = this.state
return (
<div>
{title}
</div>
);
}
}
export default App
render函数返回值
第一次渲染的时候必然会被调用一次,当它被调用时,会检查this.props 和this.state的变化并返回以下类型
- react元素
- 数组或fragments
- Portals:可以渲染子节点到不同的dom树中
- 字符串/数字类型
函数式组件特点
- 返回值和类组件render一样
- 没有生命周期
- 没有this关键字指向组件实例
- 没有内部状态(state)
组件的生命周期
万物皆可周期
阶段
- 挂载阶段Mount:组件第一次在dom树中被渲染的过程
- 更新阶段Update:组件状态发生改变,重新渲染更新的过程
- 卸载阶段Unmount:组件从dom树种被移除的过程
react生命周期
- componentDidMount 挂载到dom上时回调 网络请求最好的地方,可以添加一些订阅,需销毁时取消订阅
- componentDidUpdate 组件发生跟新时回调
- componentWillUnmount 组件即将被移除时回调
组件之间的通信
父传子 props
父组件
...
export class index extends Component {
constructor() {
super()
this.state = {
title: "标题"
}
}
render() {
const { title } = this.state
return (
<div>
<Header title={title} />
<Main />
<Footer />
</div>
)
}
}
...
子组件
...
import React, { Component } from 'react'
import PropTypes from 'prop-types';
export class Header extends Component {
constructor(props) {
super(props)
this.state = {
message: "hello component"
}
}
render() {
const { message } = this.state
const { title,age } = this.props
return (
<div>
<h1>{message}</h1>
<h1> {title}</h1>
<h2>{age}</h2>
</div>
)
}
}
Header.propTypes = {
title: PropTypes.string.isRequired,
age:PropTypes.number
}
Header.defaultProps = {
title:"default title",
age:18
}
export default Header
...
子传父
父
...
changeCount(count) {
this.setState({
count: count
})
}
render() {
const {count} = this.state
return (
<div>
<h1>app count:{count}</h1>
<Footer addClick={(count) => this.changeCount(count)} />
</div>
)
}
...
子
...
increment() {
this.setState({
count: this.state.count + 1
})
this.props.addClick(this.state.count)
}
...
组件插槽的用法
组件的children实现
每个组件都可以包含children的内容 如果只有一个内容时,不是数组的形式传递,children本身就是传递的内容
父
...
<NavBar>
<p>插入left的内容</p>
<p>插入center的内容</p>
<p>插入right的内容</p>
</NavBar>
...
子
...
render() {
const { children } = this.props
return (
<div className='navbar'>
<div className="left">
{children[0]}
</div>
<div className="center"> {children[1]}</div>
<div className="right"> {children[2]}</div>
</div>
)
}
...
props 属性传递
父
...
<NavBar2
leftSlot={<p>left 内容</p>}
rightSlot={<p>rIght 内容</p>}
/>
...
子
...
render() {
const { leftSlot, rightSlot } = this.props
return (
<div className='navbar'>
<div className="left">
{leftSlot}
</div>
<div className="center"> center</div>
<div className="right">
{rightSlot}</div>
</div>
)
}
...
组件非父子通信 Context
Context提供来一种在组件之间共享数据的方式,而不必层层传递
theme-context.js
import React from "react";
const ThemeContext = React.createContext()
export default ThemeContext
传递数据
...
import React, { Component } from 'react'
import Home from './Home'
import ThemeContext from './context/theme-context'
export class App extends Component {
constructor() {
super()
this.state = {
info: { name: 'kobe', age: 18 }
}
}
render() {
const { info } = this.state
return (
<div>
{/* 给home传递数据 */}
{/* <Home {...info}/> */}
<ThemeContext.Provider value={info}>
<Home></Home>
</ThemeContext.Provider>
</div>
)
}
}
export default App
...
使用数据
...
import React, { Component } from 'react'
import ThemeContext from './context/theme-context'
export class HomeInfo extends Component {
render() {
const { name, age } = this.context
return (
<div>HomeInfo
<p>{name},{age}</p>
</div>
)
}
}
// 设置组件ContextType 类型
HomeInfo.contextType = ThemeContext
export default HomeInfo
...
函数式组件用法
...
import ThemeContext from './context/theme-context'
function HomeBanner() {
{
<div>
<h2>homebanner</h2>
<ThemeContext.Consumer>
{
value => {
return <h2>{value.name}</h2>
}
}
</ThemeContext.Consumer>
</div>
}
}
export default HomeBanner
...
setState使用
为什么需要?
因为我们需动态监听数据的改变,以便更新到界面上,因为react没有数据劫持,所以我们需要这么一个东西来监听最新state重新渲染节目,我们必须通过setState来告知react数据已经发生改变。
setState方法是从Component继承过来的,使用组件中可以直接使用
使用
import React, { Component } from 'react'
export class App extends Component {
constructor() {
super()
this.state = {
message: "hello state",
count: 0
}
}
changeMessage() {
// 1.基本使用
// this.setState({
// message: "hello setSate"
// })
// 2.传入一个回调函数
// 可以编写一些对state的处理逻辑
// 当前的回调函数,会将之前的state和props传递进来
// this.setState((state, props) => {
// // 编写一些对新state的处理逻辑
// // 可以获取之前的state和props
// console.log(state, props)
// return {
// message: "你好啊,李银河"
// }
// })
// 3. steState在ract的事件处理中是一个异步调用
// 如果希望数据更新之后获取对应的结果执行逻辑代码,那么可以在setState中传入另外的参数 callback
this.setState({
message: "你好啊,李银河"
}, () => {
// 会在数据合并之后,自动执行
console.log("---------", this.state.message)
})
}
addCount() {
this.setState({
count: this.state.count + 1
})
}
render() {
const { message, count } = this.state
return (
<div>
<h2>App component</h2>
<p>message:{message}</p>
<button onClick={e => this.changeMessage()}>change Message</button>
<p>{count}</p>
<button onClick={e => this.addCount()}>+1</button>
</div>
)
}
}
export default App