react学习-基础部分

React教程学习

1、hello-react

  <!-- 准备好一个容器 -->
  <div id="test"></div>
  <!-- 引入有顺序 -->
  <!-- 引入核心库 -->
  <script src="../js/react.development.js"></script>
  <!-- 引入dom库,用于操作dom -->
  <script src="../js//react-dom.development.js"></script>
  <!-- 引入babel,将jsx转为js -->
  <script src="../js//babel.min.js"></script>

  <script type="text/babel">/*此处一定要写babel*/
    // 1、创建虚拟DOM
    const VDOM = <h1>hello, React</h1>; // 此处一定不要写字符串,因为不是字符串
    // 2、渲染虚拟DOM到页面
    ReactDOM.render(VDOM, document.getElementById('test'));
  </script>

2、创建虚拟DOM的方式

  • jsx

      <script type="text/babel">
        const VDOM = (
          <h1 id="title">hello jsx</h1>
        );
        ReactDOM.render(VDOM, document.getElementById('test1'));
      </script>
    
  • 原生js

    使用React自带的创建元素的方法React.createElement(标签名, 标签属性, 标签内容);

        const VDOM2 = React.createElement('h1', {id: 'title2', className:'title2'}, 'hello-React');//标签名、标签属性、标签内容
        ReactDOM.render(VDOM2, document.getElementById('test2'));
    

3、关于虚拟DOM

  • 本质是Object类型的对象(一般对象)
  • 虚拟DOM属性比较少,真实DOM属性多,因为虚拟DOM在React内部使用,无需很多属性
  • 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。

4、jsx语法规则

  • 定义虚拟DOM时,不要写引号

  • 注释render中标签时,使用**{/*

    >*/}**

  • 标签中混入js表达式时,使用{}

  • 样式的类名指定时不要用class,要用className(与ES6中的class保留字区分)

  • 内联样式要用style={{key:value}}的形式去写,且key用驼峰形式

  • 只能有一个根标签

  • 标签必须闭合

  • 标签首字母

    • 若小写字母开头,则将标签转为html同名元素,若无该标签则报错
    • 若大写字母开头,react就去渲染对应组件,若组件没有定义则报错
  • 遍历数组数据

    • 数据遍历只能用数组,不能用对象

    • 一定要用对象的话用Object.keys()获取key数组,再获取value 例如:data[key]

    • <script type="text/babel">
        const data = ['angular', 'react', 'vue'];
        const VDOM = (
          <div>
            <h1>前端jsx练习</h1>
            <ul>
              {
                data.map((item, index) => {
                  return <li key={index}>{item}</li>
                })
              }
            </ul>
          </div>
        );
        ReactDOM.render(VDOM, document.getElementById('test'));
      </script>
      

5、React组件开发

函数式组件
  • 函数:首字母大写

  • 虚拟dom挂载:使用标签

  • this指向:undefined。因为babel编译后开启了严格模式,禁止this指向Window

  •     // 创建函数式组件
        //首字母大写
        function Demo() {
          console.log(this);  //undefined,因为babel编译后开启了严格模式,禁止this指向Window
          return <h2>函数式组件(适用于简单组件)</h2>
        }
        //使用标签
        ReactDOM.render(<Demo />, document.getElementById('test'));
    	/**
         * 执行reactdom.render(<Demo />)发生过程
         *  1、react解析组件标签,找到Demo组件
         *  2、发现组件是函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现
         */
    
  • 解析过程

    • react解析组件标签,找到Demo组件
    • 发现组件是函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现
类式组件
  • 类:首字母大写

  • 虚拟dom挂载:使用标签

  • render中的this:指向类式组件的实例对象

  • // 创建类式组件
       class Demo extends React.Component {
         render() {
           //render添加到实例对象的原型对象上,供实例使用
           //render中的this,指向对象的实例对象
           return (
             <h2>类式组件(用于创建复杂组件)</h2>
           );
         };
       }
       // 渲染组件
       ReactDOM.render(<Demo />, document.getElementById('test'));
       /**
        * 执行reactdom.render(<Demo />)发生过程
        *  1、react解析组件标签,找到Demo组件
        *  2、发现组件是类定义的,随后new出该实例,并通过该实例调用原型上的render方法
        *  3、将render返回的虚拟dom转为真实dom
        */
    

6、组件实例的三大核心属性

state
区分简单组件/复杂组件
  • 通过组件状态state

    • 无state:简单
    • 有state:复杂---------类式组件实例对象有state属性
  • 初始化state

    • 使用constructor

    • class Weather extends React.Component {
           constructor(props) {
             super(props);
             //初始化状态
             this.state = {flag: false};
           };
           render() {
             console.log(this);
             return (
               <h1>今天天气{this.state.flag? '炎热' : '凉爽'}</h1>
             );
           };
         };
      
    • 获取state的值:this.state.—

    • 修改state的值--------this.setState({flag: !this.state.flag});

    • 严重注意,状态必须通过setState进行更新,且是合并,类似于小程序的setData

    • state简写
      • state数据

        class Weather extends React.Component {
              state = {flag: false};
        }
        
      • 方法

      • 自定义方法---------赋值语句+箭头函数

        class Weather extends React.Component {
            changeWeather = () =>{
                let flag = this.state.flag;
                this.setState({flag: !flag});
            };
        }
        
  • 简单给元素绑定事件

    • this.changeWeather = this.changeWeather.bind(this);

    • 今天天气{this.state.flag? ‘炎热’ : ‘凉 爽’}

    • constructor(props) {
              super(props);
              //初始化状态
              this.state = {flag: false};
              this.changeWeather = this.changeWeather.bind(this);//
            };
            render() {
              console.log(this);
              return (
                <h1 onClick={this.changeWeather}>今天天气{this.state.flag? '炎热' : '凉爽'}</h1>
              );
            };
      
            /**
             * 事件
             */
            changeWeather() {
              //由于changeWeahter是作为onclick的回调,使用不是通过实例调用的,是直接调用
              //类中的方法默认开启了局部的严格模式,所以changeWeather的this为undefined
              //console.log(this.state.flag);
              let flag = this.state.flag;
              this.setState({flag: !flag});
            };
      
props
  • 只读属性,不允许修改

  • 基本使用

    • 绑定虚拟DOM时给传参

      • ReactDOM.render(, document.getElementById(‘test’));
    • 使用时使用this.props.name

      • render() {
                return ( 
                  <h2>{this.props.name}</h2>
                );
        };
        
  • 批量传递数据

    • 使用展开运算符

      const p = {name: 'tom', age: 18};
      ReactDOM.render(<Person {...p}/>, document.getElementById('test'));
      
  • 对数据进行限制

    引入proptype.js文件

    <script src="../js//prop-types.js"></script>
    

    再为组件添加propTypes属性

    • 类型:
      • string: 类型
      • bool:布尔
      • func:函数
      • number:数字
      • array:数组
      • object:对象
      • symbol:symbol
    • isRequired:必传
    Person.propTypes = {
          name: PropTypes.string.isRequired
    };
    
  • 对数据约定默认值

    Person.defaultProps = {
          sex: '不男不女'
    };
    
  • props简写

    class Person extends React.Component {
        static propTypes = {};
    	static defaultProps = {};
        render() {};
    }
    
  • 构造器中的props:构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props

  • 函数式组件的props

    • 使用函数的参数

      function Person(props) {
          return {
              <ul>
                  <li>props.name</li>
              </ul>
          };
      };
      //添加约束
      Person.propTypes = {
            name: PropTypes.string
          };
      Person.defualtProps = {};
      
      
ref
字符串ref
  • 使用:在虚拟dom的标签中添加ref属性

    <input ref="input1" type="text" placeholder="点击按钮提示数据" />
    
    
  • 获取:使用函数时调用this.refs.input1获取标签,同getelementbyid,和vue一样

    showData = () => {
          console.log(this.refs.input1.value);
    }
    
    
回调ref
  • 内联回调
//在组件实例中添加input1属性,即该input,用this.input1调用
<input ref={cuurentNode => this.input1 = cuurentNode} type="text" placeholder="点击按钮提示数据" />

  • 如果使用内联回调函数,当更新视图时会执行两次回调,第一次为null,第二次为标签

    解决方法: 在组件实例中添加回调函数,再在ref调用

    <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" />
    
    
createRef

使用react自带的api创建一个ref

class Demo extends React.Component {
    myRef = React.createRef();
	render() {
        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
    };
}

获取标签:this.myRef.current

事件处理
  • (1).通过onXxx属性指定事件处理函数(注意大小写)

    • a.React使用的是自定义函数,------------为了更好的兼容性
    • b.React的事件是通过事件委托方式处理的(委托给组件最外层的元素)---------为了高效
  • (2).通过event.target得到发生事件的DOM元素对象----------不要过度使用ref

7、获取表单数据

非受控组件
  • 特点:标签属性值value现用现取,

    	handleSubmit = (event) => {
            event.preventDefault();
            let {username, password} = this;
            console.log(username.value, password.value);
          };
          render() {
            return (
              <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                用户:<input ref={c => this.username = c} type="text" name="username"/><br />
                密码:<input ref={c => this.password = c} type="password" name="password" /><br />
                <button>登录</button>
              </form>
            );
          };
    
    
受控组件
  • 用state记录数据,维护状态
 	state = {
        username: '',
        password: ''
      };
      handleSubmit = (event) => {
        event.preventDefault();
        let {username, password} = this;
        console.log(username.value, password.value);
      };
      userChange = (event) => {
        React.setState({username: event.target.value});
      };
      psdChange = (event) => {
        React.setState({password: event.target.value});
      }
      render() {
        return (
          <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
            用户:<input onChange={this.userChange} type="text" name="username"/><br />
            密码:<input onChange={this.psdChange} type="password" name="password" /><br />
            <button>登录</button>
          </form>
        );
      };

  • 输入处理函数合并

    	dataChange = (dataType) => {
            return (event) => {
              this.setState({[dataType]: event.target.value});
            };
          }; 
          render() {
            return (
              <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                用户:<input onChange={this.dataChange('username')} type="text" name="username" /><br />
                密码:<input onChange={this.dataChange('password')} type="password" name="password" /><br />
                <button>登录</button>
              </form>
            );
          };
    
    

8、高阶函数

定义
  • 若A函数,接收的参数是一个函数,即为高阶函数(Promise、setTimeout)
  • 若A函数,调用的返回值依然是函数,即为高阶函数
函数的柯里化
定义

​ 通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

9、组件的生命周期

卸载组件

​ ReactDOM.unmountComponentAtNode(document.getElementById(‘test’));

旧生命周期

img

组件挂载生命周期-render
      // 构造器
      constructor(props) {
        console.log('Count-constructor');
        super(props);
      };  
	  // 组件将要挂载时
      componentWillMount() {
        console.log('Count-componentWillMount');
      };
	  // 挂载dom
	  render() {
        console.log('Count-render');
      };
      // 组件已经挂载完成
      componentDidMount() {
        console.log('Count-componentDidMount');
      };
      // 组件将要卸载
      componentWillUnmount() {
        console.log('Count-componentWillUnmount');
      };

组件更新生命周期-setState
	 // 控制组件更新的‘阀门’
      shouldComponentUpdate(nextProps, nextState) {
        console.log('Count-shouldComponentUpdate');
        return true;
      };
      // 组件将要更新
      componentWillUpdate() {
        console.log('Count-componentWillUpdate');
      };
	  // 挂载dom
	  render() {
        console.log('Count-render');
      };
      // 组件完成更新
      componentDidUpdate() {
      console.log('Count-componentDidUpdate');
      };

组件更新生命周期-forceUpdate
  • (不需要更改state,强制更新)
      // 组件将要更新
      componentWillUpdate() {
        console.log('Count-componentWillUpdate');
      };
	  // 挂载dom
	  render() {
        console.log('Count-render');
      };
      // 组件完成更新
      componentDidUpdate() {
      console.log('Count-componentDidUpdate');
      };

组件更新生命周期-父组件render
  • 注意:receive函数是指父组件重新传递新参数,即第一次传递的参数无法调用该函数
      // 子组件即将传参
      componentWillReceiveProps(props) {
        console.log('B-componentWillReceiveProps', props);
      };
	 // 控制组件更新的‘阀门’
      shouldComponentUpdate() {
        console.log('Count-shouldComponentUpdate');
        return true;
      };
	  // 组件将要更新
      componentWillUpdate() {
        console.log('Count-componentWillUpdate');
      };
	  // 挂载dom
	  render() {
        console.log('Count-render');
      };
      // 组件完成更新
      componentDidUpdate(preProps, preState, snapValue) {
      console.log('Count-componentDidUpdate');
      };

总结
初始化阶段

​ 由ReactDOM.render()触发—初次渲染

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()===============>常用
    • 可以初始化一些数据,以及异步请求、订阅消息,请求成功后会调用render,
更新阶段

​ 由组件内部this.setState或this.forceUpdate或父组件render触发

  • componentWillReceiveProps(props)–父组件render触发,可接收props参数
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()
    • 在该方法中可以进行网络请求,调用setState,但是需要包裹一层条件判断,比较prevProps与this.prop中属性值或者prevState与this.state中属性值是否变化,未变化则不执行,否则会导致死循环。
卸载组件

​ 由ReactDOM.unmountComponentAtNode(组件)触发

  • componentWillUnmount() =================>常用
    • 收尾工作,关闭定时器,取消订阅消息
新生命周期

img

与旧的区别
  • componentWillMount、componentWillUpdate、componentWillReceiveProps前加UNSAFE_
  • 废除了componentWillMount、componentWillUpdate、componentWillReceiveProps钩子,增加了getDerivedStateFromProps和getSnapshotBeforeUpdate
新钩子
  • getDerivedStateFromProps少用,了解即可

    	//state的值在任何时候都取决于props
          static getDerivedStateFromProps(props, state) {
            console.log('Count-getDerivedStateFromProps');
              retrun props;
          };
    
    
  • getSnapshotBeforeUpdate

    	// 生成数据快照
          getSnapshotBeforeUpdate() {
            console.log('Count-getSnapshotBeforeUpdate');
              //snapValue,数据快照
              reuturn snapValue;
          };
    
    

10、DOM的Diff算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值