react 16.4+ 基础

1. 基础

1. 超基础API

  1. 创建react元素
    React.createElement(参数1,参数2,参数3,…)
    // 参数1元素名称
    // 参数2元素属性
    // 参数3以及以后的参数都表示元素子节点

  2. 渲染react元素
    ReactDOM.render(参数1,参数2)
    // 参数1要渲染的元素或组件
    // 参数2要渲染的元素或组件的挂载点

    例:

    const ele = React.createElement('h1',{id: 'kkk'},'Hello React')
    ReactDOM.render(ele, document.getElementById('root'))
    

    元素

2. react脚手架

使用官方的creat-react-app脚手架(集成了react+react-dom+react-router),一键搭建项目

3. jsx

jsx是javascript xml的简写,表示在javascript中写xml(html)格式的代码。
jsx是react的核心内容

  1. 属性名是驼峰命名法
    class—>className 、for—>htmlFor

    //<label for="female">Female</label>
    <label htmlFor="female">Female</label>
    <input type="radio" name="sex" id="female" />
    
  2. 推荐使用小括号包裹jsx,避免js中自动插入分号的陷阱

    const ele = (<h1>hello</h1>)
    
  3. jsx中使用js表达式【函数调用、三目表达式等等】
    语法:{js表达式}

    // 例1
    const name = '迟娜'
    const ele = (
      <h1>
        你好,我叫:{name}
      </h1>
    )
    ReactDOM.render(ele, document.getElementById('root'))
    
    
    //例2
    const flag = false
    
    const meet = ()=>{
      if(flag) {
        return (<h1>你好</h1>)
      }
      return (<h1>再见</h1>)
    }
    
    const ele = (
      <div>{meet()}</div>
    )
    
    ReactDOM.render(ele, document.getElementById('root'))
    
    //例3
    const lists = [
      {id: 1, title: 'AAA'},
      {id: 2, title: 'BBB'},
      {id: 3, title: 'CCC'}
    ]
    
    const ele = (
      <ul>
        {lists.map((item)=>{
          return (
            <li key={item.id}>
              {item.title}
            </li>
          )
        })}
      </ul>
    )
    
    ReactDOM.render(ele, document.getElementById('root'))
    
jsx的样式处理
  1. 行内样式—style
    <div style={{color:'red',backgroundColor:'yellow'}}>
    	你好
    </div>
    
  2. 类名-----className
    // css
    .kkkk {
      background-color: yellow;
    }
    
    <div className="kkkk">
    	你好
    </div>
    

4. 组件

组件是react的一等公民

1. 使用函数创建自定义组件

函数组件:使用js的函数创建的组件

  • 函数名必须是大写字母开头

  • 函数名直接作为组件标签名使用

  • 函数组件必须有返回值,表示该组件的结构【return null表示不渲染任何东西,也必须写】

    function Hello(){
      return (
        <div>
          你好,react
        </div>
      )
    }
    
    ReactDOM.render(<Hello/>, document.getElementById('root'))
    
2. class创建自定义组件

类组件:使用es6的class创建的组件

  • 类名必须是大写字母开头

  • 类组件必须继承自React.Component父类,从而可以使用父类中提供的方法或者属性

  • 类组件必须提供render()方法,render()方法必须有返回值,表示该组件的结构

    class Hello extends React.Component{
      render(){
        return (
          <div>
            Hello
          </div>
        )
      }
    }
    ReactDOM.render(<Hello/>, document.getElementById('root'))
    
React.PureComponent

PureComponent表示一个纯组件,可以用来优化React程序,减少render函数执行的次数,从而提高组件的性能。
pureComponent中的 shouldComponentUpdate() 进行的是浅比较,也就是说如果是引用数据类型的数据,数据引用地址没有变化,而数据发生改变的时候render是不会执行的。PureComponent一般会用在一些纯展示组件上。
使用pureComponent的好处:当组件更新时,如果组件的props或者state都没有改变,render函数就不会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。这是因为react自动做了一层浅比较。

3. 事件绑定
  1. 函数组件事件绑定
    function Hello(){
      function handleClick() {
        console.log('cn----Hello')
      }
      return (
        <div onClick={handleClick}>
          你好,react
        </div>
      )
    }
    
    ReactDOM.render(<Hello/>, document.getElementById('root'))
    
  2. 类组件事件绑定
    class Hello extends React.Component{
      handleClick() {
        console.log('cn----Hello')
      }
      render(){
        return (
          <div onClick={this.handleClick}>
            Hello
          </div>
        )
      }
    }
    ReactDOM.render(<Hello/>, document.getElementById('root'))
    
4. 有状态组件和无状态组件

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

  • 状态 ---- state【数据可以拆分成属性和状态,状态有一个隐含的意思,就是存在改变状态的行为。因此,不变的数据是属性props,变化的数据是状态state】
  • 函数组件没有自己的状态,只负责静态数据展示
  • 类组件有自己的状态,可以动态更新页面
组件中的state和setState()

状态(state)即数据,是类组件内部私有的数据,只能在组件内部使用,state的值是对象,表示一个组件可以有很多数据

// 例
class Hello extends React.Component {
  constructor() {
    super();
    this.state = {name: '花花'};
    this.tick = this.tick.bind(this)
  }

// 简化语法初始化state
// state = {
//     date: new Date()
// }

// button元素调用tick()方法,tick()方法的this应该指向button元素,因此必须改变this指向<Hello>组件
  tick() {
    if(this.state.name === '花花') {
      this.setState({
        name: '草草'
      });
    } else {
      this.setState({
        name: '花花'
      });
    }
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.name}.</h2>
        <button onClick={this.tick}>切换</button>
      </div>
    );
  }
}

ReactDOM.render(
  <Hello />,
  document.getElementById('root')
);
对有状态组件和无状态组件的理解以及使用场景
  1. 有状态组件

    特点:

    1. 是类组件
    2. 有继承
    3. 可以使用this
    4. 可以使用react的生命周期
    5. 使用较多,容易频繁触发生命周期钩子函数,影响性能
    6. 内部使用state,维护自身状态的变化,有状态组件根据外部组件传入的 props 和自身的 state进行渲染。

    使用场景:

    1. 需要使用到状态的。
    2. 需要使用状态操作组件的(无状态组件的也可以实现。react-hooks也可实现了)

    总结:
    类组件可以维护自身的状态变量,即组件的 state ,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。类组件则既可以充当无状态组件,也可以充当有状态组件。当一个类组件不需要管理自身状态时,也可称为无状态组件。

  2. 无状态组件

    特点:

    1. 不依赖自身的状态state
    2. 可以是类组件或者函数组件
    3. 有更高的性能。当不需要使用生命周期钩子时,应该首先使用无状态函数组件
    4. 组件内部不维护 state ,只根据外部组件传入的 props 进行渲染的组件,当 props 改变时,组件重新渲染。

    使用场景:

    1. 组件不需要管理state,用于纯展示

    优点:

    1. 简化代码、专注于 render
    2. 组件不需要被实例化,无生命周期,提升性能。
    3. 输出(渲染)只取决于输入(属性),无副作用
      视图和数据的解耦分离

    缺点:

    1. 无法使用 ref
    2. 无生命周期方法
    3. 无法控制组件的重渲染,因为无法使用shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染

    总结:
    当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。比如自定义的<Button/>、 <Input /> 等组件。

5. 受控组件与非受控组件
  1. 受控组件
    受控组件:其值受到react控制的组件成为受控组件
    众所周知,html中的表单元素是可输入的,意思就是说它有自己的可变状态。但是react中可变状态通常是保存在state中的,通过setState()方法来进行修改的。因此,react将state与表单元素值vlaue绑定到一起,这样便可以由state的值来控制表单元素的值。

    <input type="text" value={this.state.txt} onChange={e => this.setState({txt: e.target.value})}/>
    
  2. 非受控组件(DOM方式)
    借助ref使用原生DOM方式来获取表单元素值
    ref的作用:获取DOM或组件

    // 例
    class Hello extends React.Component {
      constructor() {
        super();
        // 创建ref
        this.txtRef = React.createRef()
      }
      
      handleClick = () => {
        console.log(this.txtRef.current.value)
      }
    
      render() {
        return (
          <div>
    	      // this.txtRef即可表示该input元素
    	      <input type="text" ref={this.txtRef}/>
    	      <button onClick={this.handleClick}>获取表单的值</button>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Hello />,
      document.getElementById('root')
    );
    

2. 进阶

1. 组件通讯的方式

组件通讯:组件之间进行数据传递

1. 父组件传递数据给子组件
  1. 使用props进行数据传递。组件是封闭的,要接收父组件的数据应该通过props来实现

    传递数据:直接给组件标签添加属性
    接受数据:

    1. 函数组件:通过函数参数props接受数据
      function Hello(props){ }
    2. 类组件:通过this.props接受数据
      class Hello extends React.Component {
        render() {
          return (
            <div>
              <div>
                姓名:{this.props.name}
              </div>
              <div>
                年龄:{this.props.age}
              </div>
           </div>
         );
       }
      }
      ReactDOM.render(<Hello name='jack' age={18}/>,document.getElementById('root'));
      
  2. props的特点

    1. 可以传递任意类型的数据------字符串、数组、函数等等
    2. props是只读的对象,只能读属性的值,不能修改对象
    3. 使用类组件时,如果使用了构造函数constructor,应该将props传递给super(),否则,无法在构造函数中获取props
  3. 父组件传递数据给子组件

    1. 父组件给子组件标签添加属性,值为state中的数据【要传递的数据】
    2. 子组件通过props接受父组件传递过来的数据
    class People extends React.Component{
      constructor(){
        super()
        this.state = {
          name:'花花'
        }
      }
      render(){
        return (
          <div>
            这是一个人
            <Person name={this.state.name}/>
          </div>
        )
      }
    }
    
    class Person extends React.Component{
      constructor(props){
        super(props)
      }
      render(){
        return (
          <div>
            名字是:
            {this.props.name}
          </div>
        )
      }
    }
    
    ReactDOM.render(
        <People/>,
        document.getElementById('root')
      );
    
  4. 使用 PropTypes 进行类型检查

2. 子组件传递数据给父组件

思路:利用回调函数,父组件提供回调函数(用于接受数据),将该函数作为属性值传递给子组件,子组件调用该回调函数,将要传递的数据作为回调函数的参数

class People extends React.Component{
  constructor(){
    super()
    this.state = {
      name:'花花'
    }
  }
  
  // 父组件提供给子组件的回调函数
  handleData(data){
    console.log('cn----data', data)
  }
  render(){
    return (
      <div>
        这是一个人
        <Person name={this.state.name} fn={this.handleData}/>
      </div>
    )
  }
}
	
class Person extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      data: 'hi'
    }
    this.handleClick = this.handleClick.bind(this)
  }
  handleClick() {
    this.props.fn(this.state.data)
  }
  render(){
    return (
      <div>
        <div>
          名字是:{this.props.name}
        </div>
        <button onClick={this.handleClick}>打个招呼吧</button>
      </div>
    )
  }
}

ReactDOM.render(<People/>, document.getElementById('root') );
3. 兄弟组件之间通信

思想:状态提升。通过父组件进行间接通信

4. 跨组件传递数据----Context
  1. 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件
    const { Provider, Consumer } = React.createContext()
  2. 在一个组件中使用Provider组件包裹组件,设置value属性,表示要传递的数据
  3. 另一个组件调用Consumer组件接收数据
const { Provider, Consumer } = React.createContext()

class People extends React.Component{
  render(){
    return (
      <Provider value="pink">
         <div>
           <Person/>
         </div>
       </Provider>
    )
  }
}
	
class Person extends React.Component{
  render(){
    return (
      <div>
         hhhhh
         <Consumer>
           {
           // data的值就是Provider组件中value属性值
             data => <div>{data}</div>
           }
         </Consumer>
      </div>
    )
  }
}

ReactDOM.render(<People/>,document.getElementById('root'))
5. 状态管理工具 ---- redux

状态管理工具 ---- redux

2. React16.4+组件生命周期

组件的生命周期:组件从被创建到被挂载到页面中运行,再到组件不用时卸载的过程。生命周期的每个阶段总伴随着一些方法的调用,这些方法就是生命周期的钩子函数。
钩子函数的作用:为开发人员在不同阶段操作组件提供了时机。
只有类组件才有生命周期

  1. 组件的生命周期可分成三个状态:
    Mounting(挂载):插入真实 DOM
    Updating(更新):正在被重新渲染
    Unmounting(卸载):已移出真实 DOM
  2. 组件的生命周期基本图:
    在这里插入图片描述
  3. 生命周期解析

Mounting(挂载):

  1. constructor()
    完成了React数据的初始化,只要使用了constructor()就必须写super(),否则会导致this指向错误。它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。
  2. getDerivedStateFromProps(nextProps, prevState)
    作用就是在根据当前新的 props 或者 state 来更新组件的 state,返回null则说明不需要更新state
  3. render()
    render() 方法是 class 组件中唯一必须实现的方法。创建虚拟dom,进行diff算法,更新dom树等
  4. componentDidMount()
    在组件挂载后(插入 DOM 树中)立即调用。只调用一次

Updating(更新):

  1. getDerivedStateFromProps(nextProps, prevState)
    作用就是在根据当前新的 props 来更新组件的 state,返回null则说明不需要更新state
  2. shouldComponentUpdate()
    组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render)
  3. render()
    render() 方法是 class 组件中唯一必须实现的方法。创建虚拟dom,进行diff算法,更新dom树等
  4. getSnapshotBeforeUpdate(prevProps, prevState)
    getSnapshotBeforeUpdate 会在最终的渲染之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态【可以读取但无法使用最新DOM】是可以保证与 componentDidUpdate 中一致的。返回一个值,作为componentDidUpdate的第三个参数
  5. componentDidUpdate()
    在组件更新后会被立即调用。

Unmounting(卸载):

  1. componentWillUnMount()
    在组件卸载及销毁之前直接调用。

Error Handling(错误处理)

  1. componentDidCatch(error,info)
    任何一处的javascript报错会触发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值