• React基础
  • React-Router,专门做路由的
  • PubSub,消息管理
  • Redux,集中式状态管理的库
  • Ant-Design,ui组件库
React简介
  • 中文官网
  • 用于构建用户界面的javaScript库
  • 是一个将数据渲染为HTML视图的开源javaScript库

为什么要学?
原生js,操作DOM繁琐,效率低,且会进行大量的重绘重排,且没有组件化编码方案,代码复用率低

优点
  • 采用组件化模式,声明式编码,提高开发效率和组件复用率
  • 在React Native中可以使用React语法进行移动端开发
  • 使用虚拟Dom+优秀的Diffing算法,尽量减少与真实Dom的交互

总结一下特点

  • 声明式编码
  • 组件化编码
  • React Native编写原生应用
  • 高校,优秀的Diffing算法

相关的js库

  • react.js React核心库
  • react-dom.js 提供操作DOM的react扩展库
  • babel.min.js 解析jsx语法代码转为js代码的库,类似es6转es5中有使用
jsx的hello word 示例
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>hello React</title>
</head>

<body>
  <!-- 准备容器 -->
  <div id="test"></div>
  <!-- 引入react,development必须先引入,全局多了React -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作dom,全局多了ReactDOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- 引入babel,用于jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js">
  </script>
  <!-- 此处一定要写babel,不能默认js -->
  <script type="text/babel">
      // 创建虚拟dom,jsx不加单引号,因为不是字符串
      const VDOM = <h1>Hello, React!</h1>;
      // 渲染虚拟dom到页面
      ReactDOM.render(
        VDOM,
        document.getElementById('test')
      );
  </script>
</body>

</html>
js的hello word 示例
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>hello React</title>
</head>

<body>
  <!-- 准备容器 -->
  <div id="test"></div>
  <!-- 引入react,development必须先引入,全局多了React -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作dom,全局多了ReactDOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  </script>
  <script type="text/javascript">
      // 创建虚拟dom,createElement(标签名, 属性对象, 标签内容)
      const VDOM =React.createElement(
        'h1',
        null,
        'Hello, React!'
      );
      // 渲染虚拟dom到页面
      ReactDOM.render(
        VDOM,
        document.getElementById('test')
      );
  </script>
</body>

</html>
jsx和js的区别,为啥用jsx
  • jsx创建虚拟dom更简便
  • js
const VDOM = React.createElement(
      'h1',
      { id: title },
      React.createElement(
        'span',
        null,
        'Hello, React!'
      )
);
  • jsx,创建虚拟dom更简便
const VDOM = <h1 id='title'>Hello,<span>变化的</span> React!</h1>;
虚拟DOM
   const VDOM = <h1 id='title'>Hello,<span>变化的</span> React!</h1>;
   const TDOM = document.getElementById('test')
   console.log(VDOM,'虚拟dom');
   console.log(TDOM,'真实dom');

在这里插入图片描述

  • 1,本质是Object类型的对象(一般对象)
  • 2,虚拟dom比较‘轻’(自身携带的属性少),真实dom比较重(自身携带的属性多)
  • 3,虚拟dom最终会被react转化为真实dom,展现在页面上
jsx介绍
  1. 全程javaScript XML
  2. react定义的一种类似xml的js扩展语法:js+xml
  3. 本质是React.createElement()的语法糖
  4. 作用,简化DOM
  5. jsx不是字符串,不要写引号,也不是html/xml标签
  6. jsx渲染js表达式,只能渲染表达式,需要花括号{ }包裹
  7. jsx渲染css,不能采用class,使用className
  8. jsx内联样式,采取双花括号{{key:value}}
  9. jsx只能有一个根标签,不能有多个
  10. jsx的标签首字母, 若小写开头,在转html过程中,若html无该对应的标签同名,则报错
  11. jsx的标签首字母, 若大写开头,则去渲染对应的组件,若组件没有定义,则报错
  12. 标签必须闭合,类似下面的input
  13. jsx最终产生的就是一个js对象
<style>
    .title {
      background: blue;
    }
  </style>
 <!-- 变量和样式和内联样式-->
 <script type="text/babel">
    const name = 'Hello,'
    //根标签仅有一个
    const VDOM = <div>
      <h1 className='title'>{name}<span style={{ color: 'white', fontSize: '16px' }}>变化的</span> React!</h1><h1 className='title'>{name}<span style={{ color: 'white', fontSize: '16px' }}>变化的</span> React!</h1>
      <input type="text"/>
    </div>;
    ReactDOM.render(
      VDOM,
      document.getElementById('test')
    );
  </script>

jsx渲染表达式

注意区分js语句和js表达式

  • 表达式,一个表达式会产生一个值,可以放在任何一个需要值的地方
  • 类似:a,a+b,num(),arr.map(),function num()
  • 语句(代码),控制代码走向,没有值
  • 类似,if判断,for循环,switch等
<script type="text/babel">
    const data = [1, 2, 3, 4, 5]
    //data.map是js表达式,有返回值,循环必须有惟一的key值
    const VDOM = <div>
      <ul>
        {
          data.map((item, index) => {
            return <li key={index}>{item}</li>
          })
        }
      </ul>
    </div>;
    ReactDOM.render(
      VDOM,
      document.getElementById('test')
    );
  </script>
模块与组件
  • 模块,向外提供特定功能的js程序,一般就是一个js文件
  • 组件,用来实现局部功能的代码和资源集合(html/css/js/image)
  • 模块化的应用,应用的js都以模块编写,
  • 组件化的应用,应用是多组件实现的
React面向组件编程
常用游览器开发插件
  1. 扩展商店搜 React Developer Tools
创建组件
函数式组件,用函数定义的组件

注意事项:
1,组件的首字母必须大写
2,函数必须有返回值
3,渲染的时候必须要写组件标签

  1. 实现流程:
  2. React解析组件Mydemo组件标签,找到Mydemo组件
  3. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟dom转为真实dom,随后呈现在页面上
<script type="text/babel">
    //创建函数式组件
    function Mydemo(params) {
      console.log(this);
      //undefined,babel编译完开启严格模式,严格模式下禁止this指向windows
      return <h2>我是用函数定义的组件</h2>
    }
    // 渲染组件到页面,不对,不能直接把组件这么渲染
    // ReactDOM.render(demo, document.getElementById('test'))
    ReactDOM.render(<Mydemo/>, document.getElementById('test'))
  </script>
类式组件,用类定义的组件

介绍一下类的基本知识
1,类中的构造器不是必须写的(可省略),要对实例进行初始化操作的时候,如添加指定属性的时候
2,如果a继承b,且b有构造器,且a类的super必须调用
3,类中所定义的方法,都是放在类的原型对象上,供实例使用
在这里插入图片描述
在这里插入图片描述

注意事项:
1,组件的首字母必须大写
2,类里必须有render()
3,render()里面必须有return

  1. 实现流程:
  2. React解析组件Mydemo组件标签,找到Mydemo组件
  3. 发现组件是使用类定义的,随后new出来该类的实例,然后通过该实例调用到原型上的render的方法
  4. 将render返回的虚拟dom转为真实dom,呈现到页面上
 <script type="text/babel">
    //react的类,必须继承React.Component
    class MyDemo extends React.Component {
      // render是放在MyDemo原型对象上,供实例使用
      // render的this,指向是MyDemo组件实例对象
      render() {
        return <h2>我是用类定义的组件</h2>
      }
    }
    //<MyDemo />,react帮你new了个实例
    ReactDOM.render(<MyDemo />, document.getElementById('test'))
  </script>
两者区别

在这里插入图片描述

构造器constructor
  • 可省略
  • 在react中,构造器仅能用于以下两种情况
  • 1,通过给this。state赋值对象来初始化内部state
  • 2,为事件处理函数绑定实例
  • 注意:constructor()函数中不要调用setState()方法,如果你的组件使用内部state,直接在构造函数中为this.state赋值初始化state
  • 注意: super(props)要在其它语句之前调用,否则可能会出现未定义的bug
  • 注意:构造器是否想通过this访问props,想就要将props传递给super
  //构造器的使用
    class Weather extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          isUser: false,
          name: '乞力马扎罗',
          newname: '罗曼蒂克',
        }
        this.changeName = this.changeName.bind(this)
      }
      render() {
        const { isUser, name, newname } = this.state
        return <h2 onClick={this.changeName}>我是用复杂组件,我叫{isUser ? name : newname}</h2>
      }
      changeName(params) {
        const { isUser } = this.state
        this.setState({
          isUser: !isUser
        })
      }
    }
  • 省略构造器的使用
    class Weather extends React.Component {
      state = {
        isUser: false,
        name: '乞力马扎罗',
        newname: '罗曼蒂克',
      }
      changeName = (params) => {
        const { isUser } = this.state
        this.setState({
          isUser: !isUser
        })
      }
      render() {
        const { isUser, name, newname } = this.state
        return <h2 onClick={this.changeName}>我是用复杂组件,我叫{isUser ? name : newname}</h2>
      }
    }
React属性新变化(和Vue区别)
  • 样式class,变为className
  • 行内样式style={},变为style={{}}
  • 事件点击onclick,变为onClick,React所有onxxx都变为onXxx
  • 事件点击οnclick=“demo()”,变为onClick={demo}
组件实例的三大核心属性
  • 类组件中render方法中的this为组件实例对象
  • 自定义组件的方法的this是undefined
state
  • state是组件对象最重要的属性,值是对象
  • 组件被成为状态机,通过更新组件到state来更新对应的页面显示
初始化state方法
  • 构造器constructor里面初始化state的值
  • 直接通过state={ }赋值
自定义方法的绑定this的方式

强制绑定this,通过函数对象的bind()

  • this.changeName = this.changeName.bind(this)重写方法,挂载新方法到实例对象自身,传递实例对象

箭头函数

  • 采用赋值语句+箭头函数绑定this,获取不到this时候会向外层去获取, changeWeather = () => {this.setState({ temperature: ‘33’ });}
setState修改状态值
  • state的数据不能直接修改或更新,需通过setState
  • this.setState({isUser: !isUser}),this.setState更改state状态值
  • this.setState是个合并动作,不会删除其它属性
类的属性调用 次数
  • 构造器constructor,只会调用一次
  • render,会调用1+n次,1是初始化的1次,n是点击setState状态更新的n次
  • 自定义方法,点几次,调用几次
<script type="text/babel">
    // 简单组件
    class MyDemo extends React.Component {
      render() {
        return <h2>我是简单</h2>
      }
    }
    //有状态组件/复杂组件
    class Weather extends React.Component {
      constructor(props) {
        super(props)
        // 初始化状态
        this.state = {
          isUser: false,
          name: '乞力马扎罗',
          newname: '罗曼蒂克',
        }
        // 解决changeName的this丢失问题,传递了Weather实例对象
        // 将原型上的changeName挂载给当前Weather实例对象自身
        // 这的bind相当于重写方法挂载this.changeName,如果这里改名,下面onClick={this.changeName}调用也得改名
        this.changeName = this.changeName.bind(this)
      }
      render() {
       // 读取状态
        const { isUser, name, newname } = this.state
        return <h2 onClick={this.changeName}>我是用复杂组件,我叫{isUser ? name : newname}</h2>
      }
      changeName(params) {
        //changeName放在weather原型上,供实例使用
        //changeName只能实例调用,通过Weather实例调用changeName,changeName的this就是Weather实例
        //this.changeName方法里面this丢失,因为changeName作为onClick的回调,不是实例调用,是直接调用
        //类中的方法开启默认局部严格模式,所以changeName的this丢失,为undefined
        console.log(this);
         // this.state.isUser = !this.state.isUser
        //注意:state状态数据不支持直接修改,借助内置api,this.setState更改
        const { isUser } = this.state
        //更新状态
        this.setState({
          isUser: !isUser
        })
      }
    }
    //这里的this丢失,所以不能使用,方法1 ,外层定义that,Weather缓存this,但不建议这样使用
    // function changeName(params) {
    //   console.log("点击事件,修改isUser", this.state.isUser);
    //   console.log("点击事件,修改isUser", that.state.isUser);
    // }
    ReactDOM.render(<MyDemo />, document.getElementById('test'))
    ReactDOM.render(<Weather />, document.getElementById('test2'))
  </script>

在这里插入图片描述
在这里插入图片描述

state属性精简写法
 <script type="text/babel">
    class Weather extends React.Component {
      // 初始化状态
      state = {
        temperature: 20 // 初始温度
      }
      render() {
        const { city, temperature } = this.state;
        return (
          <div>
            <h1 className='title'>Weather in {city}</h1>
            <p>Temperature: {temperature}°C</p>
            <p onClick={this.changeWeather}>修改天气</p>
          </div>
        );
      }
      // 自定义方法,采用赋值语句+箭头函数绑定this,获取不到this时候会向外层去获取
      changeWeather = () => {
        this.setState({ temperature: '33' });
      }
    }
    const VDOM = <div>
      <Weather city='Beijing' temperature={20} />
    </div>
    //渲染组件到页面
    ReactDOM.render(
      VDOM,
      document.getElementById('test')
    );
  </script>
props
  • props是只读的
  • 组件上直接传输,this.props获取
<!-- 引入prop-types,用于对组件标签属性进行限制 -->
  <script type="text/javascript" src="../js/prop-types.js">
  </script>
  <script type="text/babel">
    class Person extends React.Component {
      render() {
        const { name, sex, age } = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age}</li>
          </ul>
        );
      }
    }
    //引入prop-types 标签属性进行限制,speak是函数类型,name是字符串类型且必传
    Person.propTypes = {
      name: PropTypes.string.isRequired,
      speak: PropTypes.func
    }
    // 标签属性进行默认值设置
    Person.defaultProps = {
      name: '张三', //默认值
    }
    //渲染组件到页面
    ReactDOM.render(
      <Person name='Beijing' sex='男' age='20' />,
      document.getElementById('test')
    );
    //渲染组件到页面,name传number类型,会报错
    const p = { name: 1, sex: '男', age: '20' }
    function speak(params) {
      console.log('hello');
    }
    ReactDOM.render(
      <Person {...p} speak={speak} />,
      document.getElementById('test1')
    );
  </script>
props简写(类组件使用)
  <!-- 引入prop-types,用于对组件标签属性进行限制 -->
  <script type="text/javascript" src="../js/prop-types.js">
  </script>
  <script type="text/babel">
    class Person extends React.Component {
      // 引入prop-types 标签属性进行限制
      static propTypes = {
        name: PropTypes.string.isRequired,
        speak: PropTypes.func
      }
      // 标签属性进行默认值设置
      static defaultProps = {
        name: '张三', //默认值
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age}</li>
          </ul>
        );
      }
    }

    //渲染组件到页面
    ReactDOM.render(
      <Person name='Beijing' sex='男' age='20' />,
      document.getElementById('test')
    );
    //渲染组件到页面,name传number类型,会报错
    const p = { name: 1, sex: '男', age: '20' }
    function speak(params) {
      console.log('hello');
    }
    ReactDOM.render(
      <Person {...p} speak={speak} />,
      document.getElementById('test1')
    );
  </script>
函数组件使用props
  • props直接使用即可
	// 函数组件
    function Person2(props) {
      const { name, sex, age } = props
      return (
        <ul>
          <li>姓名:{name}</li>
          <li>性别:{sex}</li>
          <li>年龄:{age}</li>
        </ul>
      );
    }

    ReactDOM.render(
      <Person2 {...p} speak={speak} />,
      document.getElementById('test2')
    );
ref
字符串的ref
class Person extends React.Component {
      showDate = () => {
        // 通过ref获取input的真实DOM元素,但不建议使用
        console.log(this.refs.inputRef);
        const { inputRef } = this.refs
        alert(inputRef.value)
      }
      showDate2 = () => {
        // 通过ref获取input的真实DOM元素
        console.log(this.refs.inputRef2);
        const { inputRef2 } = this.refs
        alert(inputRef2.value)
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <div>
            <input ref='inputRef' type="text" placeholder='点击按钮提示数据' />
            <button ref='buttonRef' onClick={this.showDate}>提示</button>
            <input ref="inputRef2" type="text" placeholder='失去焦点提示数据' onBlur={this.showDate2} />
          </div>
        );
      }
    }
    ReactDOM.render(
      <Person />,
      document.getElementById('test')
    );
回调函数ref写法(建议使用)
  • 以这样的内联函数的方式定义的,在更新过程中会执行两次,第一次传入参null,第二次会传入dom元素
  • 原因:每次渲染的时候会创建一个新的函数实例,所以react清空旧的,设置新的
  • 初始化执行两次,但打印一次,第一次随render执行
  • 更新内容的时候执行两次,打印两次
  • 解决办法:通过将ref的回调函数定义成class的绑定函数的方式,可以避免打印两次

方式1

    class Person extends React.Component {
      // 回调函数,默认传的参数是当前元素的真实DOM
      // this就是当前组件的实例对象,把ref当前的节点挂载在实例自身上,并且取名input1
      showDate = () => {
        // 通过ref获取input的真实DOM元素,但不建议使用
        console.log(this.input1);
        alert(this.input1.value)
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <div>
            <input ref={c => this.input1 = c} type="text" placeholder='点击按钮提示数据' />
            <button ref='buttonRef' onClick={this.showDate}>提示</button>
          </div>
        );
      }
    }
    ReactDOM.render(
      <Person />,
      document.getElementById('test')
    );

方式2 class的绑定函数 建议使用

  saveInput = c => {
        this.input2 = c
        console.log(this.input2);
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <div>
            <input ref={this.saveInput} type="text" placeholder='点击按钮提示数据2' />
            <button ref='buttonRef' onClick={this.showDate}>提示</button>
          </div>
        );
      }
createRef形式(建议使用)
  • 通过React.createRef()创建一个ref容器对象
  • createRef是专人专用的,只能放一个,后者替换前者
<script type="text/babel">
    // 类组件
    class Person extends React.Component {
      // 通过React.createRef()创建一个ref容器对象
      myRef1 = React.createRef()
      myRef2 = React.createRef()
      showDate = () => {
        // 通过ref获取input的真实DOM元素
        console.log(this.myRef1);
        alert(this.myRef1.current.value)
      }
      showDate2 = () => {
        // 通过ref获取input的真实DOM元素
        console.log(this.myRef2);
        alert(this.myRef2.current.value)
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <div>
            <input ref={this.myRef1} type="text" placeholder='点击按钮提示数据' />
            <input ref={this.myRef2} type="text" placeholder='失去焦点提示数据' onBlur={this.showDate2} />
            <button ref='buttonRef' onClick={this.showDate}>提示</button>
          </div>
        );
      }
    }
    ReactDOM.render(
      <Person />,
      document.getElementById('test')
    );
  </script>
事件处理

1,通过onXxx属性指定事件处理函数,注意大小写
2,React使用的是自定义事件,而不是使用的原生dom事件(为了更好的兼容性)
3,React中的事件是通过事件委托方式处理的(委托给最外层元素,为了高效)
4,不要过度使用ref,可以通过event.target得到发生事件的dom元素对象

   showDate3 = (e) => {
        console.log(e.target);
        alert(e.target.value)
      }
      render() {
        const { name, sex, age } = this.props
        return (
          <div>
            <input type="text" placeholder='失去焦点提示数据' onBlur={this.showDate3} />
          </div>
        );
      }
非受控组件
  • 页面中输入类的值现用现取,不会提前存储
  • 得用ref
受控组件(类似双向绑定)
  • 页面中输入类的值会实时保存在状态中,需要用的时候直接从状态中取
  • 采取state状态
  <script type="text/babel">
    // 创建类组件
    class Person extends React.Component {
      handleSubmit = (e) => {
        // 阻止表单提交的默认行为
        e.preventDefault();
        const { username, sex, age } = this;
        alert(`用户名:${username.value}, 性别:${sex.value}, 年龄:${age.value}`);
      }
      // 非受控组件,现用现取
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            用户名:<input type="text" ref={c => this.username = c} /><br />
            性别:<input type="text" ref={c => this.sex = c} /><br />
            年龄:<input type="text" ref={c => this.age = c} /><br />
            <button>登录</button>
          </form>
        );
      }
    }
    ReactDOM.render(
      <Person />,
      document.getElementById('test')
    );
    class Person2 extends React.Component {
      // 初始化状态
      state = {
        username: '',
        sex: '',
        age: ''
      }
      saveUsername = (e) => {
        this.setState({
          username: e.target.value
        })
      }
      saveAge = (e) => {
        this.setState({
          age: e.target.value
        })
      }
      saveSex = (e) => {
        this.setState({
          sex: e.target.value
        })
      }
      handleSubmit = (e) => {
        // 阻止表单提交的默认行为
        e.preventDefault();
        const { username, sex, age } = this.state;
        alert(`用户名:${username}, 性别:${sex}, 年龄:${age}`);
      }
      // 受控组件,页面中输入类的值会实时保存在状态中,需要用的时候直接从状态中取
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            用户名:<input type="text" onChange={this.saveUsername} /><br />
            性别:<input type="text" onChange={this.saveSex} /><br />
            年龄:<input type="text" onChange={this.saveAge} /><br />
            <button>登录</button>
          </form>
        );
      }
    }
    ReactDOM.render(
      <Person2 />,
      document.getElementById('test2')
    );
  </script>
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐