1.React (基础篇)

React介绍:

  专门构建于用户界面的js库(顶多它是mvc中的v层框架)
  核心思想,通过数据操作视图。
  官方(推荐使用)脚手架:create-react-app
  中文网:https://react.docschina.org/

  难点:英文、webpack
  背景:react 是 Facebook 出品,背景大、生态比较丰富(pc、安卓、ios都适用)
  相对vue来说只是写法不一样,思想都类似的,代码相对vue来说要多一点点。基本上都是原生,自己写的功能多一些。

组件声明方式:

    react通过声明一个类(函数)来创建UI的
      1. class Person extends React.Component{} (类的申明方式有:状态、this、生命周期。hooks 出现之前,推荐用这种方式申明。)
      2. function Child(props, ref) {} (hooks 出现之后,函数式组件也是必须要会的,比类组件更新。)
  

搭建 react 项目

初学推荐使用脚手架: create-react-app

    npx create-react-app my-app (my-app 自己起的文件名)
    cd my-app
    npm start    /    yarn start

React 全家桶:

react 、 react-router-dom 、 redux(mobx) 、 第三方UI库antd 、 react-native(移动应用) 、 开发原生APP

react:(学习的内容)

      jsx语法
      state
      props
      数据的通信
使用:

// 1.引包 react 、react-dom
import React from 'react'; //主要的库
import ReactDOM from 'react-dom'; //把jsx转成能够让浏览器识别的工具

// 3.热更新:(可用可不用)
if(module.hot){
    module.hot.accept();
}
/*  
    挂在组件。(根节点的挂载)
    *** ReactDOM.render()是个方法。三个参数:
        第一个参数:
            模板、组件
        第二个参数:
            挂载的根节点
        第三个参数:
            挂载完成之后触发的回调函数
*/
// 2.ReactDOM.render
ReactDOM.render(
    <div>你好,世界!!!!
        <input
            // defaultValue = {'123'}
            value = {'456'}
            onChange = {()=>{
                
            }}
        />

    </div>,
    document.getElementById('root'),
    ()=>{
        console.log('挂载成功')
    }
);

jsx

jsx -> javascript + xml 一种js和自定义写法的混合模式
jsx 语法主要是为了更好的读、写模板或者组件。
jsx 语法浏览器是不识别的,通过babel的方式吧jsx转成浏览器识别的代码(babel : www.babeljs.cn)。
在react中,写<div></div>,其实就等同于写了一个 React.createElement('div',children:[],'click','active')

jsx规则:

  1.遇到样式中的 class ,直接变成className
  2.标签必须闭合 (/),特别是单标签要注意
  3.{}
    *1)里面放js代码,可以运行(运算) 比如:{console.log(1+'1')}
    *2)默然帮你展开数组
      [1,2,3] - > 1 2 3
      [<li />,<li />]如果数组中的值为组件(列表),那么一定要给列表中的每一项加key(key:一个唯一的值),为了优化
    3)注释 {// 或者 /*2/}
    *4)可以申明函数,但不能直接调用
    5)value={a} 赋值某个元素的属性
    6)设置style={{width:'200px',height:'200px',...}} 花括号包着一个对象
  4.表单元素设置默认值(value='xxx')的时候会报错,因为它认为input为一个受限的组件。value值是动态就会操作数据(value就一定会变化),会变化,就一定要有事件(onChange),所以才会报错。
    比如:<input value="1"/> 报错
 
    两种方式解决:
      1.给表单元素加上事件(onChange)(受控组件,官方推荐使用)
        <input
          value = {a}
          onChange = {()=>{
          }}
        />
      2.定义默认值的时候就使用 defaultValue (非受控组件)
        <input
          defaultValue = '123'
        />
  5.<img src={require('./images/地址.png')} alt=""/> 用img引入图片的时候,要包{require('地址')}的方式
    * 循环数据渲染的时候,引入图片地址会出现无法加载的问题:
    解决:
      1. src={require(""+地址)},括号中放 地址+空字符串。并且图片要在同级目录下,也就是不能出现  ../   
      2. 把相同的绝对路径写在 字符串里 -->  src={require(" ../相同的路径/xxx "+地址)} 。此时可以出现  ../   
  
  6.用 ref 来快速找到DOM元素
    1)给元素绑定 ref <div ref = "a" > </div> 
    2)用 this.refs.a 来获取相对应的元素。

定义组件的方式:(参考课件:2019-01-15_React -> app -> arc -> index3.js )

import React from 'react'; //主要的库
import ReactDOM from 'react-dom'; //把jsx转成能够让浏览器识别的工具

//热更新
if (module.hot) {
    module.hot.accept();
}

//组件:申明一个类。***一定要注意:类的首字母要大写(App)。
//组件在挂在的时候,会先执行construction,只会执行一次,然后经过几个钩子函数之后,走到render,
//只要数据发生变化,就再次执行render,而construction 是不会再改变
class App extends React.Component {
    constructor(props){
        super(props); //super的作用: 1.传参 2.拿this
        console.log(props)
    }
    render(){     
        //普通的render中的return上面写逻辑,return下面是UI       
        let {aaa,bbb,ccc} = this.props
        return(
            <div>
                <h1>组件</h1>
                <div>{aaa}{bbb}{ccc}</div>
            </div>            
        )
    }
}

//组件的申明:可以是个类,还可以是一个函数
function Ppa(){
    return(
        <div>
            <h1>组件2</h1>
        </div>
    )
}

/*
    属性中如果有两个重复的,后面会把前面的覆盖
    ...[a,b,c]
    ...{a:'1',b:2,}
*/
ReactDOM.render(
    <div>
        {/* <App aaa='你好' bbb='世界' ccc={[1,2,3]} /> */}
        <App {...{
            aaa:'hello',
            bbb:'word',
            ccc:[4,5,6]
        }}/>
        <Ppa/>
    </div>,
    document.getElementById('root'),
);
  1. 第一种
  class App extend React.Component{}
  1. 第二种
        在import React,{Component} from 'react'; 引 Component
    class App extend Component{ // 推荐使用 class,类名首字母要大写
      render(){
        <div>
          <h1>组件1</h1>
        </div>
      }
    }
  1. 第三种
    function Ppa(){
      return(
        <div>
          <h1>组件2</h1>
        </div>
      )
    }

写方法的时候,如果不对函数做处理,事件函数中的this指向undefined

  解决方案:
    1.使用create-app (推荐使用这种)
      click = () => {} //把匿名箭头函数赋值给click
    2.bind,this

      click(){}
 
      constructor(){
        this.click = this.click.bind(this)
      }

    3.

      click(){}

      <button
        onClick={this.click.bind(this)}
      >

    4.

      click(){}

      <button
        onClick={(e,i)=>this.click(e)}
      >

state 状态

  操作状态中的数据,就能操作视图
    constructor(){
      this.state={num: 0}
    }
  操作数据不能直接使用this.state.num = 1
  只能通过this.setState()去修改你的状态

    this.setState({ //(推荐使用这种)
      num: 3
    }, () => {
      console.log(this.state.num);
    })

   // 第二种
  this.setState((state) => {
      return { num: state.num + 1 }
    }, () => {
      console.log(this.state.num);
    })

setState 是同步还是异步的?

props数据之间的通信:(单向数据流) / 生命周期

父级传子级:
  传递数据在组件身上使用属性的绑定
    推荐使用:
      <App {...{
        xxx:'hello',
        bbb:'word',
        ccc:[4,5,6]
      }}/>
  子组件接收
    this.props.xxx

//以上知识点的综合应用(小todu)之 app.js(父级)
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import List from './list';

class App extends Component {
  constructor(props) {
    super(props);
    /*
      state 等同于 Vue中的data:
        data() {
          return {        
          }
        }
    */
    this.state = {
      val: '',
      arr: ['第一个li']
    };
  }
  /*
    改变数据状态使用 this.setState()
  */
  change = (ev) => {
    this.setState({
      val: ev.target.value
    })
  }
  keyup = (ev) => {
    if (ev.keyCode === 13) {
      let { arr, val } = this.state;
      arr.push(val)
      this.setState({ arr ,val:''});
    }
  }

  render() {
    let { val, arr } = this.state;
    let list = arr.map((e, i) => {   //循环产生一堆<li> </li>
      return <List {...{        //map方法会返回一个新数组[<li></li>,<li></li>,...],map方法一定要return,jsx的{}会自动展开数组
        key: i,             //尽量保证key的值是唯一的
        val: e             //val和key是固定写法,val是<li>的innerText
      }} />
    });

    return (
      <div className='App'>
        <input
          value={val}
          onChange={this.change}
          onKeyUp={this.keyup}
        />
        <ul>
          {list}
        </ul>
      </div>
    );
  }
}

export default App;
//子组件 (list.js)
import React, {Component} from 'react'
class List extends Component{
    render(){
        return(
            <li>{this.props.val}</li>   //接收父级的数据
        );
    }
}

export default List;

获取DOM元素

  1. 给元素标记 ref
    <input type="text" ref="username" onChange={this.showThis}/>
  2. 获取
    console.log(this.refs.username.value)

父级获取子级的值和方法

下面用一个父组件(Father.js)和子组件(Child.js)来演示如何能拿到值和方法:

方法一:

给子组件添加属性 ref=‘childData’<Child ref='childData'></Child>
然后在父组件用 this.refs.childData.xxx 的方式拿值

console.log(this.refs.childData.state) // 拿到子组件中state中的值
console.log(this.refs.childData.run()) // 拿到子组件中run方法

方法二:

给子组件添加 onRef={(ref) => { this.child = ref; }}
<Child onRef={(ref) => { this.child = ref; }}></Child>
然后在子组件中添加生命周期的 componentDidMount 这个方法:

componentDidMount() {
     if (this.props.onRef) {
        this.props.onRef(this);
     }
}

然后在父组件用 this.child.xxx 的方式拿值

console.log(this.child.state);
console.log(this.child.run();

方法三:

在父组件创建ref容器:this.pw = React.createRef()

constructor(props) {
    super(props);
    // 方法3:创建用来保存ref标识的标签对象的容器
    this.pw = React.createRef()
}

然后给子组件添加属性:ref={this.pw}
<Child ref={this.pw}></Child>
然后就可以在父组件用 this.pw.current 拿到子组件值和方法:

console.log(this.pw.current.state);
console.log(this.pw.current.run();

空元素、空标签

react 需要在组件或其他地方加个包裹层,可能会用div包裹,但是又不想有真实的DOM节点,可以用以下空标签包裹

<React.Fragment> </React.Fragment>
<></> 它也具有非常好的速记语法,仅在最新版本(和Babel 7+)中受支持:

优化,减少不必要的 刷新(render)

查看更多
用 PureComponent 代替 Component

import React, { Component, PureComponent } from 'react';
export default class App extends PureComponent{
  render() {
    return(
       <></>
    )
  }
};

强制触发 render

首先改变 state 或者 props 就可以触发组件的刷新,除此之外,react 还专门提供了一个方法this.forceUpdate()

import React, { PureComponent } from 'react';
export default class Test extends PureComponent {

  componentDidUpdate() {
    alert("组件刷新了");
  };

  render() {
    return (
      <button onClick={() => this.forceUpdate()}>刷新组件</button>
    )
  };
};
posted @ 2019-01-15 19:51  真的想不出来  阅读(266)  评论(0编辑  收藏  举报