React第二章 基础知识讲解

122 阅读6分钟

第一节、理解react和react-dom两个库

1、react的api是很少的,学一次就不用了,基本就是js功力。

2、react设计之初就是用jsx来描述UI,所以解耦了dom操作。

react 做逻辑层。

react-dom 做渲染层,操作虚拟dom,挂载页面。

3、移动端、可以使用别的渲染库来做。

第二节、剖析JSX的实质

1、jsx语法即 js 和 html 的混合体,实际的核心逻辑是用js实现的。

2、常见的代码如下

ReactDOM.render(<App/>,document.getElementById('root'));

3、jsx的实质就是React.createElement的 反复调用。

4、我们react里面的通常写法:

class HelloLxq extends React.Component{
    render(){
        return(
            <div>
                Hello {this.props.name}
            </div>
        );
    }
}

ReactDOM.render(
    <HelloLxq name="lxq"/>,
    document.getElementById('hello-lxq')
)

5、实际上JSX的写法

class HelloLxq extends React.Component{
  render(){
    return React.createElement(
     'div',
      null,
     'Hello',
      this.props.name
    );
  }
}
ReactDOM.render(
    React.createElement(
        HelloLxq,
        {name:'lxq'}
    ),
    document.getElementById('hello-lxq')
);

第三节、state & setState  == 渲染 & 更新

1、在组件里面我们用 {} 在 jsx里面渲染变量值。

2、如果数据需要修改,并且需要页面同时响应变化,那就需要把变量放在state里面,同时使用 steState修改。

3、初始化状态


// 初始化状态
this.state = {
    count:0
}

4、更新状态使用 steState, 不能直接 this.state.count = xxx


// 更新状态
this.setState({
    count: this.state.count + 1
})

5、注意事项:

5.1、setState 是异步的,底层设计(性能优化)同一个生命周期会批量操作更新 state

5.2、setState第二个参数可选,是一个回调函数,可以拿到最新的state

5.3、setState第一个参数可以是一个function, 需要返回{}。函数的params: prevState、prevProps。用来

处理修改state时需要依赖上一次的state值。如下:

this.setState((prevState,prevProps)=>({
      count:prevState.count+1
}),() => {
      // 这里可以获取到最新的state
      console.log(this.state.count);
})

6、手敲一遍

import React, { Component } from 'react'

export default class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            msg1: '您好呀,我是state里面的msg1',
            count: 0,
        }
    }
    // 这里的写法和 constructor 里面的 this.state = {} 是一样的
    // state = {
    //     msg1:'您好呀,我是state里面的msg1'
    // }
    componentDidMount() {
        // this.setState({
        //     count: this.state.count + 1
        // }, () => {
        //     console.log(this.state.count,'这里是后输出,update后的最新值');
        // })
        // console.log(this.state.count,'这里是先输出');

        // 如果修改的 state 是依赖上一次的 state 可以这么写
        // this.setState((prevState, prevProps)=>{
        //     return {
        //         count: prevState.count+1
        //     }
        // })

        // 上面代码的简略写法
        this.setState((prevState, prevProps) => ({
            count: prevState.count + 1
        }), () => {
            console.log(this.state.count, '这里是后输出,update后的最新值');
        })
        console.log(this.state.count, '这里是先输出');
    }
    render() {
        const msg = "大家好,我是lxq";
        return (
            <div>
                <p>欢迎学习react!</p>
                <p>{msg}</p>
                <h1>{this.state.msg1}</h1>
                <h2>{this.state.count}</h2>
            </div>
        )
    }
}

第四节、props 基础使用

1、父组件向子组件传递属性利用props接收

2、使用例子如下:


// 父组件传入
<PropsDemo title="hello world!"></PropsDemo>
// 子组件接收
// class组件使用
<h1>{this.props.title}</h1>
// 函数型组件使用
function xxx (props){
    return (
        <h1>{props.title}</h1>
    )
}

3、手敲一遍

App.js

import PropsDemo from './child/PropsDemo'
...
render() {
  return (
    <div>
      ...
      <PropsDemo title="hello world!"></PropsDemo>
    </div>
  )
}

PropsDemo.js

// class 组件
// import React, { Component } from 'react'
// export default class PropsDeom extends Component {
//     render() {
//         return (
//             <div>
//                 {this.props.title}
//             </div>
//         )
//     }
// }

// 函数式组件
import React from 'react'

// export default function PropsDemo(props) {
//     return (
//         <div>
//             {props.title}
//         </div>
//     )
// }

// 参数解构
export default function PropsDemo({ title }) {
    return (
        <div>
            {title}
        </div>
    )
}

第五节、条件渲染 & 数据循环

1、条件渲染写法、一般使用三目表达式


// 1.三目表达式写法
{this.state.show?<h2>{this.props.titel}</h2>:null}

// 2.在render函数里面使用变量装载结果
let result = this.state.show?<h1>{this.props.title}</h1>:null;
{result}

// 3.直接写if else 
let result
if(this.state.show){
	result = (<h1>{this.props.title}</h1>)
}else{
	result = null
};
{result}

2、数据循环渲染写法


class Loop extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            goods:[
            {title:'webpack教程',price:19.8},
            {title:'vue教程',price:29.8},
            {title:'react教程',price:39.8},
            {title:'node教程',price:49.8},
          ]
        }
  }
  
  render(){
    return <div>
        <ul>
          {this.state.goods.map(item=>{
          	return <li key={item.title}>
              	<span>{item.title}</span>
              	<span>&yen;{item.price}</span>
             </li>
          })}
        </ul>
    </div>
  }
}

3、手敲一遍

Condition.js

import React, { Component } from 'react'

export default class Condition extends Component {
    constructor(props){
        super(props);
        this.state = {
            showTitle:true
        }
        setTimeout(() => {
            this.setState({
                showTitle:false
            })
        }, 3000);

    }
    render() {
        // 第2种写法
        // let result = this.state.showTitle?<p>{this.props.title}</p>:null;
        // 第3种写法
        let result 
        if(this.state.showTitle){
            result = <p>{this.props.title}</p>;
        }else{
            result = null;
        }
        return (
            <div>
                <h3>数据条件渲染展示</h3>
                {/* 第1种写法 */}
                {/* {this.state.showTitle?<p>{this.props.title}</p>:null} */}
                {/* 第2种写法 */}
                {result}
            </div>
        )
    }
}

Loop.js

import React, { Component } from 'react'

export default class Loop extends Component {
    constructor(props) {
        super(props);
        this.state = {
            goods: [
                { title: 'webpack教程', price: 19.8 },
                { title: 'vue教程', price: 29.8 },
                { title: 'react教程', price: 39.8 },
                { title: 'node教程', price: 49.8 },
            ]
        }
    }
    render() {
        return <div>
            <h3>{this.props.title}</h3>
            <ul>
                {this.state.goods.map(item=>(
                    <li key={item.title}>
                        <span>{item.title}</span>
                        <span>&yen;{item.price}</span>
                    </li>
                ))}
            </ul>
        </div>
    }
}

第六节、事件

1、点击事件为例,使用方法如下

// 小驼峰,事件名称用{}包裹

<button onClick={xxx}></button>

2、由于React的 this 指向问题,事件绑定有四种写法:

2.1、利用bind绑定,这种写法很少少用 。点击传参- no


// 在constructor里面利用bing绑定this,解决方法this的指向问题

constructor(props){
    super(props)
    this.switchShowTitle = this.switchShowTitle.bind(this);
}

switchShowTitle() {
    this.setState()
}

<button onClick={this.switchShowTitle}>切换显示</button>

2.2 利用bind绑定,这种写法很少用 。点击传参-使用bind


// 在constructor不绑定this的指向
constructor(props){
    super(props)
}

switchShowTitle(param) {
    console.log(param);
    this.setState()
}

<button onClick={this.switchShowTitle.bind(this,'点击参数')}>切换显示</button>

2.3 利用 = 号赋值,加上箭头函数,这种写法常用 。点击传参-使用bind


// 在constructor不绑定this的指向
constructor(props){
    super(props)
}

switchShowTitle = (param)=>{
    console.log(param);
    this.setState()
}

<button onClick={this.switchShowTitle}>切换显示</button>

2.4 事件上直接使用箭头函数调用, 这种写法常用。点击传-正常


// 在constructor不绑定this的指向
constructor(props){
    super(props)
}

switchShowTitle(param) {
    console.log(param);
    this.setState()
}
<button onClick={() => this.switchShowTitle('点击参数')}>切换显示</button>

3、手敲一遍

EventFn.js


import React, { Component } from 'react'

export default class EventFn extends Component {
    constructor(props) {
        super(props);
        // 第1种
        // this.switchShowTitle = this.switchShowTitle.bind(this);
        this.state = {
            showTitle: true
        }
    }
    // 第1、2、4种
    switchShowTitle(param) {
        console.log(param);
        this.setState((prevState, prevProps) => ({
            showTitle: !prevState.showTitle
        }))
    }
    // 第3种
    // switchShowTitle = (param) => {
    //     console.log(param);
    //     this.setState((prevState, prevProps) => ({
    //         showTitle: !prevState.showTitle
    //     }))
    // }
    render() {
        return (
            <div>
                {this.state.showTitle ? <h3>{this.props.title}</h3> : null}
                {/* 第1种 */}
                {/* <button onClick={this.switchShowTitle}>切换显示</button> */}
                {/* 第2种 */}
                {/* <button onClick={this.switchShowTitle.bind(this,'点击')}>切换显示</button> */}
                {/* 第3种 */}
                {/* <button onClick={this.switchShowTitle}>切换显示</button> */}
                {/* 第4种 */}
                <button onClick={() => this.switchShowTitle('点击参数')}>切换显示</button>
            </div>
        )
    }
}

第七节、样式编写

1、行内样式编写

<img style={{width:"100px", height:"100px"}} />

2、添加class 类名、属性

<img className="border-1px" />
<img className={className} alt={title}/>

第八节、实现双向数据绑定

1、React实现input的双向数据绑定要点

1.1、动态绑定value属性

1.2、监听input的onChage事件

2、手敲一遍

TwoWayDataBind.js


import React, { Component } from 'react'

export default class TwoWayDataBind extends Component {
    constructor(props) {
        super(props)
        this.state = {
            inputVal: 'default-value'
        }
    }
    // 绑定input的change事件
    // 函数1可行
    // inputOnChange(e) {
    //     this.setState({
    //         inputVal: e.target.value
    //     })
    // }
    // 函数2可行
    inputOnChange = (e) => {
        this.setState({
            inputVal: e.target.value
        })
    }
    render() {
        return (
            <div>
                <h3>{this.props.title}</h3>
                <input type="text" value={this.state.inputVal} onChange={e => this.inputOnChange(e)} />
                <p>{this.state.inputVal}</p>
            </div>
        )
    }
}

第九节、生命周期 基础使用

1、示意图

2、生命周期钩子


// 组件构建
    constructor(props) {}

// 组件将要挂载
    componentWillMount() {console.log('我们会 获取数据,操作方法')}
    
// 组件render渲染
    render(){}

// 组件已经挂载
    componentDidMount() {console.log('我们会 操作dom')}

// 接收父组件传递的属性有变化, 作相应的响应
    componentWillReceiveProps() {console.log('我们会 处理异步得到的数据')}

// 组件是否需要更新,返回布尔值,优化点
    shouldComponentUpdate(nextProps, nextState) {
    // 使用该方法让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,
    // 而且该方法并不会在初始化渲染或当使用forceUpdate()时被调用,我们要做的只是这样:
    return nextState.someData !== this.state.someData
    // 但是,state里的数据这么多,还有对象,还有复杂类型数据,react的理念就是拆分拆分再拆分,这么多子组件,我要每个组件都去自己一个一个对比吗??
    // 不存在的,这么麻烦,要知道我们的终极目标是不劳而获-_-
    // React.PureComponent 可以看一下
}

// 组件将要更新
    componentWillUpdate() {}

// 组件已经更新
    componentDidUpdate() {}

// 组件将要销毁
    componentWillUnmount() {console.log('我们会 清除计时器')}


3、手敲一遍

LifeCycle.js


import React, { Component } from 'react'

class LifeCycleSon extends Component {
    constructor(props) {
        console.log('0.生命周期-组件正在构建');
        super(props)
        this.state = {
            title: '子组件内容'
        }
    }
    // componentWillMount rename UNSAFE_componentWillMount
    componentWillMount() {
        // 可以进行API的调用,数据获取,不能dom操作
        console.log('1.生命周期-组件将要挂载');
    }
    componentDidMount() {
        // 可以进行dom操作,对我们的状态进行更新操作
        console.log('3.生命周期-组件已经挂载');
    }
    componentWillReceiveProps() {
        console.log('4.生命周期-组件获取父级属性更新');
    }
    shouldComponentUpdate() {
        console.log('5.生命周期-组件是否需要更新,需要返回Boolean值')
        return true
    }
    componentWillUpdate() {
        console.log('6.生命周期-组件将要更新');
    }
    componentDidUpdate() {
        console.log('7.生命周期-组件已经更新');
    }
    componentWillUnmount() {
        console.log('8.生命周期-组件将要销毁');
    }
    render() {
        console.log('2.生命周期-组件render');
        return (
            <div>
                <p>{this.state.title}</p>
                <p>{this.props.context}</p>
            </div>
        )
    }
}

export default class LifeCycle extends Component {
    constructor(props) {
        super(props)
        this.state = {
            sonText: '父级传值-默认值',
            isShowSon: true,
        }
        setTimeout(() => {
            this.setState({
                sonText: (<b>父级传值-改变了</b>),
            })
        }, 2000);
        setTimeout(() => {
            this.setState({
                isShowSon: false,
            })
        }, 4000);
    }
    render() {
        return (
            <div>
                <h3>组件生命周期演示</h3>
                {this.state.isShowSon ? <LifeCycleSon context={this.state.sonText}></LifeCycleSon> : '子组件已销毁'}
            </div>
        )
    }
}

基本使用总结完了,系统讲解了一下常用方式,后面提升内容还在持续更新!💻