react 基础

react 官方脚手架 create-react-app 的使用

  • 全局安装脚手架

    $ npm install create-react-app -g
    
  • 创建项目

    $ create-react-app 项目名称   # 项目名不能是大写字母
    
    # OR
    $ npx create-react-app 项目名称  # 先检测有没有安装脚手架,没有就先本地安装,再创建项目
    

react 介绍

react 起源于 Facebook 的内部项目,后发现这套框架好用,在 2013年5月开源了。react 并不是完整的 MVC/MVVM 架构,它专注于提供清晰、简洁的 View 层解决方案。它也是对虚拟 DOM 进行操作,提高性能。

jsx 语法

  • JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换成纯 JavaScript 后由浏览器执行。在实际开发中,JSX 在产品打包阶段都已经编译成纯 JavaScript,不会带来任何副作用,反而让代码更加直观并易于维护。编译过程由 Babel 的 JSX 编译器实现的。

<React.StrictMode> 严格模式作用:

  1. 识别不安全的生命周期
  2. 关于使用过时的字符串 ref API 的警告
  3. 检测意外的副作用
  4. 检测过时的 context API

组件

  • 组件的书写规范

    • 组件首字母必须大写,否则会被认为是原生 dom 节点
    • 组件最外层需要有一个根元素,不能有兄弟节点
    • return 后面加上小括号可以回车
    • 组件可以嵌套
    • 组件的函数式写法和 class 类写法
    • 样式
      • class 换成 className
      • 行内样式,注意 小驼峰写法
    // 引入 react
    import React from 'react'
    // 引入外部样式
    import './index.css'
    
    // 函数式写法 定义组件
    function App () {
      return (
        <div>
          <p style={{background: "pink"}}>行内样式</p>
          <p className="box">class 外部样式</p>
        </div>
      )
    }
    
    // class 类写法 定义组件
    class App extends React.Component {
      render () {
        return (
          <div>
            <p className="box">这是使用 class 定义的组件</p>
            <div style={ {color: 'red'} }>我是 div 元素</div>
            <Child></Child> 
          </div>
        )
      }
    }
    
    // 定义子组件
    class Child extends React.Component {
      render () {
        return (
          <div>
            <p className="box">我是 child 组件</p>
          </div>
        )
      }
    }
    
    // 导出组件
    export default App
    
    
    • 事件绑定(需要注意 this 指向问题)
    import React from 'react'
    
    export default class App extends React.Component {
      render () {
        return (
          <div>
            <label>用户名:<input ref="username" type="text"/></label> <br />
                
            <button onClick={ () => console.log(this.refs.username.value) }>提交1</button>
            <button onClick={ this.handleClick2.bind(this) }>提交2</button>
            <button onClick={ this.handleClick3 }>提交3</button>
          </div>
        )
      }
      handleClick2 () {
        console.log(this.refs.username.value)
      }
    
      handleClick3 = () => {
        console.log(this.refs.username.value)
      }
    
      /* 改变 this 指向问题
            call(this, 1, 2)     改变 this 指向,并自动调用函数
            apply(this, [1, 2])  改变 this 指向,并自动调用函数
    
            bind(this, 1, 2)     改变 this 指向,不自动调用函数
      */
    }
      // 这里使用的ref官网已不再推荐,具体用法如下
    
    • ref 新用法
    import React from 'react'
    
    export default class App extends React.Component {
      username= React.createRef();
      // this.username.current 获取的是 input 的真实 dom
      render () {
        return (
          <div>
            <label>用户名:<input ref="{this.username}" type="text"/></label> <br />
                
            <button onClick={ () => console.log(this.username.current.value) }>提交</button>
          </div>
        )
      }
    }
    
    • 事件传参方式
    <button onClick={ () => this.deleteRow(id) }>Delete Row</button>
    <button onClick={ this.deleteRow.bind(this, id) }>Delete Row</button>
    
    • state 状态
    import React, { Component } from 'react'
    
    export default class App extends Component {
        // es6 语法
        constructor () { 
          super()  // super 必须写
          this.state = {
            msg: '信息'
          }
        }
        
        // es7 语法,等价于上面的 es6 写法
        state = { 
          msg: '信息'
        }
    
        render() {
          return (
            <div>
               <p>{ this.state.msg }</p>
               <button onClick={this.clickHandle}>修改 msg 状态</button>
            </div>
          )
        }
    
        clickHandle = () => {
            /* setState() 并不保证是同步执行的,
            	  当 setState() 在同步代码中执行时,它将是异步执行,第二个参数是个回调函数,
            	  	并且会进行 batchUpdate 批处理
            	  当 setState() 在异步代码中执行时,它将是同步执行
            */
            this.setState({   // state 状态不能直接修改,只能通过 setState() 来修改
                msg: '修改了'
            }, callback)
        }
    }
    

注意:将 html 字符串,解析成 html 标签

<div  dangerouslySetInnerHTML={{ __html: this.state.html }} />

条件渲染

  • 在 react 中使用与运算符(&&)、三目运算符进行条件渲染

    import React, { Component } from 'react'
    
    export default class App extends Component {
      state = {
        isShow: true,
        list: []
      }
    
      render() {
        return (
          <div>
            {
              this.state.list.length > 0 && <div>条件为真时渲染</div>     
            }
                
            {
              this.state.isShow ?
                <div>条件为真时渲染</div> :
                <div>条件为假时渲染</div>
            }
          </div>
        )
      }
    }
    
  • 阻止组件渲染

    import React, { Component } from 'react'
    
    class Child extends Component {
        render () {
            // 传递来的数组长度为 0,就阻止组件渲染,直接返回 null
            if (!this.props.list.length) return null
    
            return <div>child 组件</div>
        }
    }
    
    export default class App extends Component {
      state = {
        list: []
      }
    
      render() {
        return (
          <div>
            <Child list={ this.state.list }/>
          </div>
        )
      }
    }
    
    

列表渲染

  • 使用 map() 方法渲染列表

    import React, { Component } from 'react'
    
    export default class App extends Component {
      state = {
        list: [111, 222, 333]
      }
    
      render() {
        return (
          <ul>
            {
              this.state.list.map((item, index) => <li key={index}>{item}</li>)
            }
          </ul>
        )
      }
    }
    
    

父与子组件通信

  • 在子组件上通过 key = value 写属性传递数据,子组件内通过 this.props 获取属性

  • 注意在传递参数时,如果写成 isShow = “true” ,是一个字符串;如果写成 isShow = {true},是一个布尔值

  • prop 的类型验证和默认值

    import React, { Component } from 'react'
    // 引入 prop-types 模块
    import myPropTypes from 'prop-types'
    
    class NavBar extends Component {
      render() {
        return (
          <div style={{ background: 'pink' }}>
            <p>这是 子组件</p>
    
            <div>{this.props.title}</div>
            {
              this.props.isShow ?
              <button>按钮</button>
              : null
            }
          </div>
        )
      }
    
      // prop 类型验证
      static propTypes = {
        title: myPropTypes.string,
        isShow: myPropTypes.bool
      }
    
      // prop 默认值
      static defaultProps = {
        title: "标题",
        isShow: true
      }
    }
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <p>这是父组件</p>
            <NavBar title="导航栏" isShow={false}></NavBar>
            <NavBar></NavBar>
          </div>
        )
      }
    }
    
    
  • 插槽

    import React, { Component } from 'react'
    
    class Child extends Component {
      render () {
        return (
          <div>
            <p>child</p>
    
            {/* 整体插入 */}
            {this.props.children}
    
            {/* 单个插入 this.props.children 是个数组*/}
            {this.props.children[0]}
          </div>
        )
      }
    }
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <p>app</p>
    
            <Child>
              <div>插槽内容1</div>
              <div>插槽内容2</div>
            </Child>
          </div>
        )
      }
    }
    
    
    

子与父组件通信

  • 给子组件传递一个回调函数,在子组件中触发这个回调函数,并将数据传递给父组件

    import React, { Component } from 'react'
    
    class Child extends Component {
      state = {
        msg: 'child 的数据'
      }
    
      render () {
        return (
          <div>
            <p>child</p>
            {/* 触发父组件传递来的回调函数,并将数据传递给父组件 */}
            <button onClick={ () => this.props.myEvent(this.state.msg) }>
                向父组件传递数据
            </button>
          </div>
        )
      }
    }
    
    export default class App extends Component {
      render () {
        return (
          <div>
            <p>father</p>
            <Child myEvent={ this.getChildData } />
          </div>
        )
      }
    
      getChildData = (data) => { // 用来获取子组件数据的回调函数
        console.log(data)
      }
    }
    
    

ref 标记组件通信

  • 通过 ref 给组件做标记。适合给子组件做标记

    import React, { Component } from 'react'
    
    class Child extends Component {
      state = {
        msg: 'child 数据'
      }
    
      render () {
        return (
          <div>
            <p>child----msg: { this.state.msg }</p>
          </div>
        )
      }
    
      setMsg = (data) => {
        this.setState({
          msg: data
        })
      }
    }
    
    export default class App extends Component {
      render () {
        return (
          <div>
            <p>father</p>
            <button onClick={ () => this.refs.child.setMsg('修改 msg 数据') }>
               click me
            </button>
            <Child ref="child" />
          </div>
        )
      }
    }
    
    

非父子关系组件通信

  1. 状态提升,使用父与子、子与父组件的通信方式,关系复杂时,容易掉头发,不推荐

  2. 利用发布订阅模式,实现事件总线机制

    import React, { Component } from 'react'
    
    // 实现事件总线
    const bus = {
      list: {},
    
      $on: function (eventName, callback) {
        this.list[eventName] = callback
      },
    
      $emit: function (eventName, payload) {
        payload ? this.list[eventName](payload) : this.list[eventName]()
      }
    }
    
    class Son extends Component {
      state = {
        msg: 'son 数据'
      }
      render () {
        return (
          <div>
            <p>son</p>
            {/* 发布数据 */}
            <button onClick={ () => bus.$emit('getSonData', this.state.msg) }>
              publish
            </button>
          </div>
        )
      }
    }
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <p>app</p>
            <Son />
          </div>
        )
      }
    
      componentDidMount () {
        // 订阅数据
        bus.$on('getSonData', (data) => {
          console.log(data)
        })
      }
    }
    
    
  3. Context 状态树通信(跨级通信)

    import React, { Component } from 'react'
    
    const MyContext = React.createContext()
    
    class Son extends Component {
      render() {
        return (
          // 消费者,里面是个回调函数,context 就是生产者 value 传过来的数据
          // 通过 context 改变根组件状态
          <MyContext.Consumer>
            {
              context => (
                <div>
                  <p>son 组件</p>
                  <button onClick={() => context.setMsg("修改了")}>修改 App 状态</button>
                </div>
              )
            }
          </MyContext.Consumer>
        )
      }
    }
    
    class Child extends Component {
      render() {
        return (
          <div>
            <p>child 组件</p>
            <Son />
          </div>
        )
      }
    }
    
    export default class App extends Component {
      state = {
        msg: '数据'
      }
    
      render() {
          
        const obj = {
          msg: this.state.msg,
          setMsg: (data) => { // 提供一个修改状态的方法,供消费者调用
            this.setState({
              msg: data
            })
          }
        }
    
        return (
          // 生产者,value 是固定的,值为要通信的数据
          <MyContext.Provider value={obj}>
            <div>
              <p>app---{this.state.msg}</p>
              <Child />
            </div>
          </MyContext.Provider>
        )
      }
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值