react基础(一)

React组件基础

  1. 组件的两种创建方式:函数组件和类组件

  2. 无状态(函数)组件,负责静态结构展示

  3. 有状态(类)组件,负责更新组件UI,让页面动起来

  4. 绑定事件注意this指向问题

  5. 推荐使用受控组件来处理表单

  6. 完全利用JS语言的能力创建组件,这是React的思想

    使用函数创建组件

    function Hello(){
    return (
    <div>这里是函数组件</div>
    )
    }
    //const Hello=()=><div>这里是函数组件<div>
    ReactDOM.render(<Hello/>,document.getElementById("root"))

    使用类创建组件

    class Hello extends React.Component{
    render(){
    return <div>这里是类组件</div>
        //null
    }
    }
    ReactDOM.render(<Hello/>,document.getElementById("root"))

事件绑定

//类组件
class App extends React.Component{
    handleClick(){
        console.log("单机事件触发")
    }
    render(){
        return(
            <button onClick={this.handleClick}>事件触发</button>
        )
    }
}
export default App
//函数组件
function App(){
    function handleClick(){
        console.log("单机事件触发")
    }
    return  <button onClick={handleClick}>事件触发</button>
}
export default App

事件对象

  • 可以通过事件处理程序获取到事件对象

  • React中的事件对象叫做:合成事件(对象)

  • 合成事件:兼容所有浏览器,无需担心浏览器兼容性问题

class App extends React.Component{
    handleClick(e){
        //阻止浏览器的行为默认行为
        e.preventDefault()
        console.log("打印跳转去百度")
    }
    render(){
        return <a href="https://www.baidu.com" onClick={this.handleClick}>跳转到百度</a>
    }
}
ReactDOM.render(<App/>,document.getElementById("root"))

有状态组件和无状态组件

  • 函数组件又叫做无状态组件,类组件又叫做有状态组件

  • 状态(state)即数据

  • 函数组件没有自己的状态,只负责数据展示(静)

  • 类组件有自己的状态,负责跟新UI,让页面"动"起来

class App extends React.Component{
    //constructor(){
    //    super()
    //    this.state={
    //        count:0
    //    }
    //       this.handleClick=this.handleClick.bind(this)
    //}
    //简化语法
    state={
        count:0
    }
    handleClick(){
        this.setState({
            count:this.state.count+1
        })
    }
    render(){
        return 
        <div>
            <h1>数字:{this.state.count}</h1>
            <button onClick={()=>this.handleClick()}>点击加一</button>
       { /*<button onClick={()=>{
                   this.setState({
            count:this.state.count+1
            
           }) 
         }}>点击加一</button>*/}
        </div>
    }
}
ReactDOM.render(<App/>,document.getElementById("root"))

表单处理

受控组件

class App extends React.Component{
    state={
        txt:""
    }
render(){
return <input value={this.state.txt}  onChange={e=>this.setState({
            txt:e.target.value
        })}/>
}
}
ReactDOM.render(<App/>,document.getElementById("root"))

非受控组件(不推荐,直接操作DOM)

class App extends React.Component{
    constructor(){
        super()
        this.txtRef=React.createRef()
    }
    handleClick(){
        console.log(this.txtRef.current.value)
    }
    render(){
        return (
        <div>
            <input ref={this.txtRef}/>
             <button onClick={this.handleClick}>获取文本框的值</button>
        </div>
        )
    }
}

组件通讯

组件的props

组件是封闭的,要接收外部数据应该通过props来实现

props的作用:接收传递给组件的数据

传递数据:给组件添加组件

接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据

//函数组件
//2.接收数据
const Hello=(props)=>{
    return (
        <div>接收到传递来的数据:{props.name}</div>
    )
}
//1.传递数据
ReactDOM.render(<Hello name="Bob"/>,document.getElementById("root"))
//类组件
//2.接收数据
class App extends React.Component{
    render(){
        return (<div>接收到传递来的数据:{this.props.name}</div>)
    }
}
//1.传递数据
ReactDOM.render(
    <Hello 
        name="Bob" 
        age={19} 
        colors={["red","green","blue"]} 
        fn=()=>{console.log("props可以传递任意类型的数据")}
        tag={<p>这是一段jsx</p>}
        ></Hello>,
     document.getElementById("root"))

proprs的特点:

  1. 可以给组件传递任意类型的数据

  2. props是只读的对象,只能读取属性的值,无法修改对象

  3. 注意:使用类组件时,如果写了构造函数(constructor),应该将props传递给super(),否则,无法在构造函数中获取到props !

    class Hello extends React.Component{
        constructor(props){
            //推荐将props传递给父类构造函数
            super(props)
        }
        render(){
            //本来就可以拿到,不受任何影响
            return (<h1>{this.props.name}</h1>)
        }
    }
    ReactDOM.render(<Hello name="Bob"/>,document.getElementById("root"))

    #####

组件通讯的三种方式

  1. 父组件->子组件

  2. 子组件->父组件

  3. 兄弟组件

父组件给子组件传参:

  • 父组件提供要传递的state的数据

  • 给组件标签添加属性,值为state中的数据

  • 子组件中通过props接收父组件中传递的数据

//父组件
class Father extends React.Component{
    state={
        hisname="塔兹米"
    }
    render(){
     return (<div>
             <Child name={this.state.hisname}/>    
            </div>)
    }
}               
//子组件
const Child = props =>(<div>{props.name}</div>)

子组件给父组件传参:

  • 利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数

  • 父组件提供一个回调函数(用于接收数据)

  • 将该函数作为属性的值,传递给子组件

  • 子组件通过props调用回调函数

  • 将子组件的数据作为参数传递给回调函数

//父组件
class Father extends React.Component{
    state={
        parentmsg:""
    }
    Childmassage=(msg)=>{
        console.log(msg)
        this.setState({
            parentmsg:msg
        })
    }
    render(){
        return(
            <div>
              父组件数据:{this.state.parentmsg}
            <Child kk={this.Childmassage}/>
            </div>
        )
    }
}
//子组件
class Child extends React.Component{
    state={
        apple:"苹果"
    }
    passMsg=()=>{
        this.props.kk(this.state.apple)
    }
    render(){
        return (<div onClick={this.passMsg}></div>)
    }
}

兄弟组件传参:

  • 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态

  • 思想:状态提升

  • 公共父组件提升:提供共享状态;提供操作共享状态的方法

  • 要通讯的子组件只需通过props接收状态或者操作状态的方法

Context

作用:跨组件传递数据(比如:主题、语言)

使用步骤:

1.调用React.createContext() 创建Provider(提供数据)和Consumer(消费数据)两个组件

const {Provider,Consumer} = React.CreateContext()

2.使用Provider组件作为父节点

3.设置value属性,表示要传递的数据

<Provider value="pink">
    <div className="App">
    <Child1/>
    </div>
</Provider>

4.调用Consumer组件接收数据

<Consumer>
    {(data)=><span>data参数表示接收到的数据</span>}
</Consumer>

例如:

const {Provider,Consumer} = React.CreateContext()
class App extends React.Component{
    render(){
        return(
        <Provider value="pink">
         <div className="app">
         <Node/>
         </div>
        </Provider>
        )
    }
}
const Node=props =>{
    return (
        <div className="node">
        <SubNode/>
        </div>
    )
}
const SubNode = props =>{
    return(
        <div className="subnode">
        <Child/>
        </div>
    )
}
const Child=props=>{
    return(
        <div className="child">
            <Consumer> 
             {
              data=><span>接收到的数据:{data}</span>
             }
            </Consumer>
        </div>
    )
}

总结:

  1. 如果两个组件是远方亲戚(比如,嵌套多层)可以使用Context实现组件通讯

  2. Context提供了两个组件:Provider和Consumer

  3. Provider组件:用来提供数据

  4. Consumer组件:用来消费数据

Props深入

children属性

children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性

children属性与普通的props一样,值可以是任意值(文本、React元素、组件,甚至是函数)

const body=document.querySelector("body")
    const app=document.createElement("div")
    app.id="app"
    body.appendChild(app)
    class Hello extends React.Component{
    render(){
    console.log(this.props.children)
        //这里是子节点
    return 
        //这里是子节点
        (
    <h1>{this.props.children}</h1>
    )
    }
    }
    ReactDOM.render(<Hello>这里是子节点</Hello>,document.getElementById("app"))

props校验

对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据

如果传入的数据不对,可能导致组件内部报错

关键问题:组件的使用者不知道明确的错误原因

比如:

//小明创建的组件App
function App(props){
    const arr=props.colors
    const lis=arr.map((item,index)=><li key={index}>{item.name}</li>)
    //很明显小明创建的组件需要传入一个数组,然而小红却传入了一个数字
    return (
        <ul>lis</ul>
    )
}
//小红使用组件App
<App colors={19}/>
  • props校验:允许在创建组件的时候,就指定props的类型、格式等

  • 作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增加组件的健壮性

    例如:

    App.propsType = {
    colors:PropTypes.array
    }

    使用步骤

    1. 安装包prop-types(yarn add prop-types/npm i props-types)

    2. 导入props-types包

    3. 使用 组件名.propTypes={}来给组件的props添加校验规则

    4. 校验规则通过PropsTypes对象来指定

例如:

import PropType from "prop-types"
function App(props){
    return(
        <h1>{prop.color}</h1>
    )
}
App.propTypes={
    colors:PropTypes.array,
    tag:PropTypes.element,
    filter:PropTypes.shape({
        area:PropTypes.string,
        price:PropTypes.number
    })
}

约束规则

  1. 常见类型:array,bool,func,number,object,string

  2. React元素类型:element

  3. 必填项:isRequired

  4. 特定结构的对象:shape({})

//常见类型
optionalFunc:PropTypes.func,
//必选
requiredFunc:PropTypes.func.isRequired,
//特定结构的对象
optionalObjectWithShape:PropTypes.shape({
    color:PropTypes.string,
    fonSize:PropTypes.number
})

props的默认值

如果我们需要的值,props中没传入,则可以为props设置默认值

  • 场景:分页组件->每页显示条数

  • //例如:
    function App(props){
        return(
        <div>{props.pageSize}</div>
        )
    }
    //设置默认值
    App.defaultProps={
        pageSize:10
    }
    //此处没有传pageSize的值
    ReactDOM.render(<App/>,document.getElementById("root"))

组件的生命周期

  • 意义:组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能,分析组件错误原因等

  • 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用卸载的过程

  • 生命周期的每个阶段总是伴随着一些方法的调用,这些方法就是生命周期的钩子函数

  • 钩子函数的作用:为开发人员在不同阶段操作组件提供时机

  • 只要类组件才有生命周期

生命周期的三个阶段

1.创建时(挂载阶段)

  • 执行实际:组件创建时(页面加载时)

  • 执行顺序:

  • constructor()->render()->componentDidMount

//组件生命周期
class App extends React.Component{
    constructor(props){
        super(props)
        console.log("创建之时constructor()")//1
    }
    componentDidMount(){
        console.log("挂载完成后componentDidMount")//3
    }
    render(){
        console.log("渲染阶段render()")//2
        return (<h1>挂载阶段</h1>)
    }
}
  1. 钩子函数触发时机作用
    constructor创建组件时,最先执行1.初始化state;2.为事件处理程序绑定this
    render每次组件渲染都会触发渲染UI(注意:不能调用setStatus)
    componentDidMount组件挂载(完成DOM渲染)后1.发送网络请求;2.DOM操作;

2.更新时(更新阶段)

  • 执行时机:1. setState(); 2. forceUpdate(); 3. 组件接收到新的props

  • 说明:以上三者任意一种变化,组件就会重新渲染

  • 执行顺序:render-->componentDidUpdate()

钩子函数触发时机作用
render每次组件渲染都会触发渲染UI(与挂载阶段是同一个render)
componentDidUpdate组件更新(完成DOM渲染)后1.发送网络请求;2.DOM操作;3.注意:如果要setState()必须放在一个if条件中【因为直接调用setState()更新状态,也会导致递归更新!!】
class App extends React.Component{
    render(){
        console.log("渲染阶段")
        return (
        <h1>更新阶段</h1>
        )
    }
    componentDidUpdate(prevProps){
        console.log("组件更新后")
        //做法:比较更新前后的props是否相同,来决定是否重新渲染更新
        console.log("上一次的props:",prevProps,"当前的props",this.props)
        if(prevProps.count !== this.props.count){
            //this.setState({})
            //发送ajax请求
        }
    }
}

3.卸载时(卸载阶段)

执行时机:组件从页面消失

钩子函数触发时机作用
componentWillUnmount组件卸载(从页面消失)执行清理工作(比如:清理定时器等等)
class App extends React.Component{
    state={
        count:0
    }
    handleClick=()=>{
       this.setState({
           count:this.state.count+1
       })
    }
    render(){
        return (
        <div>
           {this.state.count >=3 ? <h1>子组件被卸载了,好可怜!!</h1> : <Child kk={this.state.count}/>}
                <button onClick={this.handleClick}>加一</button>
            </div>
        )
    }
}
class Child extends React.Component{
    componentDidMount(){
        //开启定时器
        this.timerId=setInterval(
           ()=>{console.log("定时器正在执行")
         },500)
    }
    render(){
        return (
        <h1>点击次数:{this.props.kk}</h1>
        )
    }
    //Chid组件被卸载时触发
     componentWillUnmount(){
        console.log("Child已经消失了")
         //清理定时器
         clearInterval(this.timerId)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值