美文网首页
JSX基本使用&React(1)

JSX基本使用&React(1)

作者: 鲜蛋卷小狐狸 | 来源:发表于2022-01-16 14:33 被阅读0次
    1. React元素的属性名使用驼峰命名法
    2. 特殊属性名:class -> className for -> htmlFor tabindex -> tabIndex
    3. 没有子节点的React元素可以用/>结束
    4. 推荐:使用小括号包裹JSX,从而避免JS中的自动插入分号陷阱
    const dv = (
       <div>hello</div>
    )
    
    1. jsx中是使用Javascript表达式
    • 数据储存在JS中
    • 语法:{JavaScript表达式} 注意不是双大括号!
    const name = 'jack'
    const dv = (
       <div>你好,我叫{name}</div>
    )
    

    6.条件渲染

    // 条件渲染
    const isLoading = true
    const loadData = () => {
      if(isLoading){
        return <div>loading...</div>
      }
      return <div>数据加载完成,此处显示加载后的数据</div>
    }
    
    const title = (
      <h1>条件渲染:{loadData()}</h1>
    )
    ReactDOM.render(title,document.getElementById('root'))
    

    还可以使用if/else三元运算符逻辑与运算符来实现

    //三元表达式
    const loadData = () => {
      return isLoading ? (<div>loading...</div>) : (<div>数据加载完成,此处显示加载后的数据</div>)
    }
    
    //逻辑与运算符
    const loadData = () => {
      return isLoading && (<div>loading...</div>)
    }
    

    isLoading是false不会执行后面的,true才会执行
    7.列表渲染

    const songs = [
      {name:'qwe',id:1},
      {name:'dfddg',id:2},
      {name:'hsd',id:3}
    ]
    
    const title = (
      <ul>
        {songs.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    )
    

    注意:

    • 列表要渲染一组数据,应该使用map()方法
    • 列表渲染应该添加key属性,key属性的值要保证唯一
    • 原则:map()遍历谁,就给谁添加key属性
    • 注意:尽量避免使用索引号作为key,索引号可变不稳定

    8.JSX样式处理

      1. 行内样式--style
    const list = (
      <h1 style={{color:'red',backgroundColor:'skyblue'}}>
        jsx样式处理
      </h1>
    )
    
      1. className样式
    //导入
    import './index.css'
    const list = (
    <h1 className="title" style={{color:'red',backgroundColor:'skyblue'}}>
        jsx样式处理
      </h1>
    )
    
    //index.css
    .title{
      text-align: center;
    }
    

    9.react组件的两种创建方式

    • 9.1 使用函数创建组件
    • 使用js函数或者箭头函数创建
    • 函数名首字母大写,react以此区分 组件 和普通的 元素
    • 函数要有return值
    • 渲染函数组件:用函数名作为组件标签名
    • 组件标签可以是单标签也可以是双标签
    function Hello(){
      return(
        <div>我的第一个react组件!</div>
      )
    }
    ReactDOM.render(<Hello />,document.getElementById('root'))
    

    箭头函数

    const Hello = () => <div>我的第一个react组件</div>
    
    • 9.2 使用类创建组件
      类组件:使用ES6的class创建的组件
      约定1:类名也必须以大写字母开头
      约定2:类名称应该继承React.Component父类,从而可以使用父类中提供的方法或属性
      约定3:类组件必须提供render()方法
      约定4:render()方法必须有返回值,表示该组件的结构
    class Hello extends React.Component{
      render(){
        return(
          <div>我的第一个react类组件!</div>
        )
      }
    }
    

    9.3 抽离为独立的js文件
    组件作为独立的个体,独立存放一个组件

    • 创建Hello.js文件
    • 在文件中导入react
    • 创建组件
    • 在Hello.js中导出该组件
    • 在index.js中导入该组件
    • 渲染组件

    10.点击事件:驼峰命名法,

    • 函数组件绑定事件
    // 通过函数组件绑定事件
    function App() {
      function handleClick(){
        console.log('函数组件中的事件绑定,事件触发了')
      }
      return(
        <button onClick={handleClick}>点我,点我</button>
      )
    }
    ReactDOM.render(<App />,document.getElementById('root'))
    
    • 类组件
    class  App extends React.Component{
        handleClick(){
            console.log('单击事件触发了')
        }
        render(){
            return(
                <button onClick={this.handleClick}>点我,点我</button>
            )
        }
    }
    ReactDOM.render(<App />,document.getElementById('root'))
    
    

    11.事件对象

    • 通过时间处理程序获取到事件对象
    • react中的事件对象叫做:合成事件(对象)
    • 合成事件:兼容所有浏览器,无需担心跨浏览器兼容性问题

    12.有状态组件和无状态组件

    • 函数组件又叫做无状态组件,类组件又叫做有状态组件
    • 状态(state)即数据
    • 函数组件没有自己的状态,只负责数据展示(静)
    • 类组件有自己的状态,负责更新UI,让页面”动“起来

    13.组件中的state和setState

    • 状态(state)即数据,是组件内部私有数据
    • state的值是对象,表示一个组件中可以有多个数据
    • 状态改变,语法:this.setState({要修改的数据}),注意,不要直接修改state中的值,这是错误!!!
    this.setState({
      number: this.number + 1
    })
    
    • setState()作用:1.修改state 2.更新UI
    • 思想:数据驱动视图

    14.抽离onclick的方法,解决this指向问题

    • 1.箭头函数,利用箭头函数自身不绑定this的特点
    class App extends React.Component{
        state = {
            count: 0, 
        }
        onIncrement() {
            this.setState({
                count: this.state.count + 1
            })
        }
        render(){
            return(
            <div>
                <h1>计数器:{this.state.count}</h1>
    //箭头函数中的this指向外部环境,此处为:render()方法
                <button onClick={()=>this.onIncrement()}>+1</button>
            </div>
            ) 
        }
    }
    
    • 2.Function.prototype.bind()
      利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起
    class App extends React.Component{
        state = {
            count: 0, 
        }
        constructor() {
          super()
          this.onIncrement = this.onIncrement.bind(this)
        }
        onIncrement() {
            this.setState({
                count: this.state.count + 1
            })
        }
        render(){
            return(
            <div>
                <h1>计数器:{this.state.count}</h1>
    //箭头函数中的this指向外部环境,此处为:render()方法
                <button onClick={this.onIncrement}>+1</button>
            </div>
            ) 
        }
    }
    
    • 3.class实例方法,推荐使用
      利用箭头函数形式的class实例方法。注意:该语法是实验性语法,但是,由于babel的存在可以直接使用
    class App extends React.Component{
        state = {
            count: 0, 
        }
        onIncrement = () => {
            this.setState({
                count: this.state.count + 1
            })
        }
        render(){
            return(
            <div>
                <h1>计数器:{this.state.count}</h1>
                <button onClick={this.onIncrement}>+1</button>
            </div>
            ) 
        }
    }
    

    15.表单处理

    • 1.受控组件
      • 由state的值来控制表单元素的值
      • 步骤:
        • 1.在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
        • 2.给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素的变化)
    class App extends React.Component{
       state = {txt:''}
        handleChange = e => {
            this.setState({
                txt:e.target.value
            })
        }
        render(){
            return(
            <div>
                <input type="text" value={this.state.txt} onChange={this.handleChange}>+1</input>
            </div>
            ) 
        }
    }
    
    • 2.多表单元素优化
      • 1.给表单增加name属性,名称与state相同
      • 2.根据表单元素类型获取对应值
      • 3.在change事件处理程序中通过[name]来修改对应的state
    <input name="txt" type="text" value={this.state.txt} onChange={this.handleChange}></input>
    
    
    //根据表单元素类型获取值
    const value = target.type === "checkbox"
      ? target.checked
      : target.value
    
    //根据name设置对应state
    this.setState({
      [name]: value
    })
    
    
    • 3.非受控组件
      借助于ref,使用原生DOM方式来获取表单元素值
      ref作用:获取DOM或组件
      使用步骤:
      • 1.调用React.createRef()方法创建一个ref对象
    construction(){
      super()
      this.txtRef = React.reacteRef()
    }
    
      • 2.将创建好的ref对象添加到文本框中
    <input type="text" ref={this.txtRef} />
    
      • 3.通过ref对象获取到文本框的值
    console.log(this.txtRef.current.value)
    

    16.组件的props

    • 组件是封闭的,要接收外部数据应该通过props来实现
    • props的作用:接收传递给组件的数据
    • 传递数据:给组件标签添加属性
    • 接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据
      父传子
      特点:
    • 可以给组件传递任意类型的数据
    • props是只读的对象,只能读取属性的值,无法修改对象
    // 2.接收数据
    const Hello = (props) => {
        console.log(props)
        props.fn()
        // 修改props的值:错误演示!!!!!!!
        // props.name = '123'
        return(
            <div>
                <h1>props:{props.name}</h1>
                {props.tag}
            </div>
        )
    }
    // 1.传递数据
    ReactDOM.render(<Hello name="jack" age={19} fn={()=>console.log('这是一个函数')} tag={<p>这是一个p标签</p>} />,document.getElementById('root'))
    
    // 2.接收数据
    class Hello extends React.Component{
        constructor(props){
            super(props)
            console.log(props)
            props.fn()
        }
        render(){
            return(
                <div>
                    <h1>props:{this.props.age}</h1>
                </div>
            )
        }
    }
    // 1.传递数据
    ReactDOM.render(<Hello name="rose" age={19} color={['red','green','blue']}  />,document.getElementById('root'))
    
    • 注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数constrauctor中获取到props!
    class Hello extends React.Component{
    //推荐将props传递给父类构=构造函数
      constrauctor(props){
        super(props)
      }
      render(){
        return (
                 <div>
                     <h1>props:{this.props.age}</h1>
                 </div>
        )
      }
    }
    

    子传父

      • 1.父组件提供一个回调函数(用于接收数据)
      • 2.自组件调用传入的函数
        兄弟组件传递
        状态提升,由兄弟组件共同的父组件管理状态
        17.Context
        跨组件传递数据
        使用步骤:
    • 1.调用React.createCcontext()创建Provider(提供数据)和Consumer(消费数据)两个组件
    const { Provider, Consumer } = React.createContext()
    
    • 2.使用Provider组件作为父节点
    • 3.设置value属性,表示要传递的数据
    <Provider value="pink">
    
    • 4.调用Consumer组件接收数据
    <Consumer>
      { data => <span>data参数表示接收到的数据 -- { data }</span> }
    </Consumer>
    
    

    18.props深入
    18.1 children属性:表示组件标签的子节点,当组件标签有子节点时,props就会有该属性

    function Hello (props){
      return(
        <div>
          组件的子节点:{ props.chihldren }
        </div>
      )
    }
    
    < Hello>我是子节点</Hello>
    

    18.2 props校验:允许在创建组件的时候,就指定props的类型、格式等

    • 对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据
    • 传入到的数据格式不对,可能会导致报错
    • 作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增加组件的健壮性
    App.propTypes = {
      colors: PropTypes.array
    }
    

    使用步骤:

      • 安装包prop-types(yarn add prop-types/npm i prop-types)
      • 导入prop-types包
    import PropTypes from 'prop-types'
    
      • 使用 组件名.propTypes = {} 来给组件的props添加校验规则
        约束规则:
        1.常见类型:array、bool、func、number、object、string
        2.react元素类型:element
        3.必填项:isRequired
        4.特定结构的对象:shape({})
    //添加props校验
    //属性a的类型 数值
    //属性fn的类型 函数并且为必填项
    //属性tag的类型 React元素(element)
    //属性filter的类型 对象({area: '上海', price: 1999})
    App,propTypes = {
      a: Proptypes.number,
      fn: Proptypes.func.isRequired,
      tag: Proptypes.element,
      filter: Proptypes.shape({
        area: Proptypes.string,
        price: Proptypes.number
      })
    }
    

    18.3 props默认值:未传入props时生效
    App.defaultProps = {
    pageSize:0
    }

    1. 组件的生命周期
      19.1 意义:组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能,分析组件错误原因等
      组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用卸载的过程
      生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数
      钩子函数 的作用:为开发人员在不同阶段操作组件提供了时机
      只有 类组件 才有生命周期
      19.2 生命周期的三个阶段
      生命周期.jpg
      1. 创建阶段(挂在阶段)
        执行时机:组件创建时(页面加载时)
        执行顺序:


        生命周期-挂载.jpg
    • 2.更新阶段
      执行时机:1.setState() 2.forceUpdate() 3.组件接收到新的props
      说明:以上三者任意一种变化,组件就会重新渲染
      执行顺序:


      生命周期-更新.jpg

      在componentDidUpdate中调用this.setState时需要加if条件语句判断

    //比较更新前后的props是否相同,来决定是否重新渲染组件
    if(prevProps.count !== this.props.count){
      this.setState({})
      //或者发送ajax请求的代码
    }
    
      1. 卸载阶段
        执行时机:组件从页面消失


        生命周期-卸载.jpg
    1. render-props和高阶组件
      20.1 React组件复用
      复用什么:1.state 2. 操作state的方法(组件状态逻辑)
      两种方式:1.render props模式 2. 高阶组件(HOC)
      1. .render props模式
    //调用
    <Mouse render={(mouse)  =>{
    ... ...
    }}></Mouse>
    
    //组件内部
    render(){
      return this.props.render(this.state)
    }
    

    children代替render属性

    //调用
    <Mouse>{() => {
    ... ...
    }}<Mouse>
    
    //组件内部
    this.props.children(this.state)
    

    组件优化:

    //添加校验
    Mouse.propsTypes = {
      children: PropTypes.func.isRequired
    }
    

    代码优化:
    1.给render props模式添加props校验
    2.应该在组件卸载时,解除mousemove事件绑定

    Mouse.propsTypes = {
      children: PropTypes.func.isRequired
    }
    
    componentWillUnmount(){
      window.removeEventListener('mousemove',this.handleMouseMove)
    }
    

    20.2高阶组件
    目的:实现状态逻辑复用
    使用步骤:
    1.创建一个函数,名称约定以with开头
    2.指定函数参数,参数应该以大写字母开头(作为要渲染的组件)
    3在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
    4.在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
    5.调用改高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中

    function withMouse(WrappedComponent){
      class Mouse extends React.Component {}
      return Mouse
    }
    
    //Mouse组件中的render方法
    return <WrappedComponent {...this.state} />
    
    //创建高阶组件
    function withMouse(WrappedComponent){
      //该组件提供复用的状态逻辑
      class Mouse extends React.Component{
        state:{
          x:0,
          y:0
        }
    
        handleMouseMove = e => {
          this.setState({
            x:e.clientX,
            y:e.clientY
          })
        }
    
        //  控制鼠标状态的逻辑
        componentDidMount(){
          window.addEventListener('mousemove',this.handleMouseMove)
        }
        componentWillUnmount(){
          window.removeEventListener('mousemove',this.handleMouseMove)
        }
    
        render(){
          return <WrappedComponent {...this.state} {...this.props} />
        }
      }
      //设置displayName
      Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`
    
      return Mouse
    }
    
    function getDisplayName(WrappedComponent){
      return WrappedComponent.displayName || WrappedComponent.name || 'Component'
    }
    
    //用来测试高阶组件
    const Position = props =>{
       return (
          <p>
            鼠标当前位置:(x:{props.x},y:{props.y})
          </p>
      )
    
    }
    
    //获取增强后的组件:
    const MousePosition = withMouse(Position)
    
    class App extends React.Component{
      render() {
         return(
          <div>
            <h1>高阶组件</h1>
            <MousePosition a='1' />
          <div/>
        )
      }
    }
    

    设置displayName

    • 使用高阶组件存在的问题:得到的两个组件名称相同
    • 原因:默认情况下,React使用组件名称作为displayName
    • 解决方式:为高阶组件设置displayName便于调试时区分不同的组件
    • displayName的作用:用于设置调试信息(React Developer Tools信息)
    Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`
    
    function getDisplayName(WrappedComponent){
      return WrappedComponent.displayName || WrappedComponent.name || 'Component'
    }
    

    传props:

        render(){
          return <WrappedComponent {...this.state} {...this.props} />
        }
        //组件MousePosition 传入的参数就不会丢失了
    

    21.setState说明
    21.1异步更新
    调用多次setState,只会触发一次render渲染
    21.2推荐语法

    this.setState((state,props)=>{
      return{
        count:state.count + 1
      }
    })
    

    回调函数形式的setState更新也是异步更新,立刻打印state,结果还是1。
    连续两次更新state加1,第二次是在第一次基础上加一的,即第二次拿到的值是2,第二次更新是在2上➕1
    21.3
    setState第二个参数

    • 场景:在状态更新(页面完成重新渲染)后立即执行
    • 语法:setState(updater,[,callback])
    this.setState(
    (state,props)=>{},
    ()=>{console.log('这个回调函数会在状态跟新后立即执行')}
    )
    

    相关文章

      网友评论

          本文标题:JSX基本使用&React(1)

          本文链接:https://www.haomeiwen.com/subject/keychrtx.html