react学习 - 组件化开发

108 阅读4分钟

组件化开发

把页面逻辑拆分成一个一个小的组件,然后整合成一个大的页面,形成一个大的组件树,每一个组件都是一个小的模块。 对于一些重复使用的逻辑我们也可以拆分成组件,减少代码量

react的组件化划分

  1. 函数式组件 Functional Component
  2. 类组件 Class Comoonent
  3. 无状态组件(Stateless Component)和有状态组件(Stateful Component)
  4. 展示型组件 (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的变化并返回以下类型

  1. react元素
  2. 数组或fragments
  3. Portals:可以渲染子节点到不同的dom树中
  4. 字符串/数字类型

函数式组件特点

  1. 返回值和类组件render一样
  2. 没有生命周期
  3. 没有this关键字指向组件实例
  4. 没有内部状态(state)

组件的生命周期

万物皆可周期

阶段

  1. 挂载阶段Mount:组件第一次在dom树中被渲染的过程
  2. 更新阶段Update:组件状态发生改变,重新渲染更新的过程
  3. 卸载阶段Unmount:组件从dom树种被移除的过程

react生命周期

  1. componentDidMount 挂载到dom上时回调 网络请求最好的地方,可以添加一些订阅,需销毁时取消订阅
  2. componentDidUpdate 组件发生跟新时回调
  3. componentWillUnmount 组件即将被移除时回调

6eee98149fbfef0363dae25eed23cc1.png

组件之间的通信

父传子 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