React开发进阶系列文章(一) - React初体验

155 阅读5分钟

1.React是什么?

  • React是由Facebook 开源的一个JS库
  • 官方解释:React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库

A JavaScript library for building user interfaces .

2.React的特点

声明式编程

  • 什么是声明式编程:

    • 它描述目标的性质,让电脑明白目标,而非流程

    • 声明式编程是告诉计算机需要计算"什么",而不是"如何" 去计算

  • 前端开发模式:

    • 声明式编程是目前整个大前端的开发的模式:Vue、React、Flutter

    • 它允许我们只需要维护自己的状态

    • 当状态改变的时候,React可以根据最新的状态去渲染我们的ui界面

  • ui = f (state)

    • ui : the layout on the screen

    • f: the build method

    • state: the app state

组件化开发

  • 组件是React中重要思想

    • 它提供了一种抽象,我们可以开发出一个独立可复用的小组件来构造我们的应用
  • 组件化思想应用

    • 有了组件化的思想,尽可能将页面拆分成一个个小的,可复用的组件

    • 这样让我们代码更方便组织和管理,并且扩展性也强

多平台适配

  • 2013年,React发布之初主要是开发Web页面
  • 2015年,Facebook推出了ReactNative,用于开发移动端跨平台(RN)
  • 2017年,Facebook推出ReactVR,用于开发虚拟现实Web应用程序

3.React 开发依赖

  • 开发React必须依赖这三个库

    • react: 包含react所必须的核心代码

    • react-dom:react渲染不同平台所需要的核心代码

    • babel:将jsx转换成react代码的工具

  • React为什么要依赖这三个库:

    • 其实, 这三个库是各司其职, 目就是让每一个库单纯做自己的事情
    • 为什么要进行拆分呢?
    • react中包含了 react 和 react-native 所共同拥有的核心代码
  • react-dom针对 web 和 native 所完成的事情不同:

    • web端:react-dom会将 jsx 最终渲染成真实的DOM, 显示在浏览器中
    • native端:react-dom会将 jsx 最终渲染成原生的控件 (比如Android中的Butto, iOS中的UIButton)

4.认识Bable

  • babel是什么:

    • 是目前前端使用非常广泛的编译器转码器
    • 可以将ES6代码转为ES5代码,从而在现有环境执行
  • ReactBabel的关系:

    • 默认情况下 React 其实可以不用 babel
    • 但前提是我们使用 React.createElement 来编写源代码, 它编写的代码非常繁琐可读性差
    • 我们就可以直接编写jsx(JavaScript XML)的语法,并且让babel帮助我们转换成React.createElement

5.Hello React 案例

  • 在界面上显示文本:hello world
  • 点击下方的一个按钮,点击后文本变成hello react

使用react之前,先用原生代码实现,与react进行对比

 <body>
    <h2 class="title">Hello World</h2>
    <button class="btn">改变文本</button>
    <script>
      // 1.定义数据
      let message = "Hello World";
      // 2.将数据显示在h2元素中
      const titleEl = document.getElementsByClassName("title")[0];
      titleEl.innerHTML = message;
      // 3.点击按钮 界面的数据发生改变
      const btnEl = document.getElementsByClassName("btn")[0];
      btnEl.addEventListener("click", (e) => {
          message = "Hello React";
          titleEl.innerHTML = message;
          console.log("按钮发生了点击")
      });
    </script>
  </body>

引入React依赖

<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <body>
    <div id="app"></div>
    <!-- 使用jsx 并且希望script中的jsx代码被解析,必须在script标签中添加一个属性 -->
    <script type="text/babel">
      // 1.渲染的内容
      let message = "Hello World"
      // 2.挂载的对象
      ReactDOM.render(<h2>{message}</h2>, document.getElementById("app"));
    </script>
  </body>
  • React.render函数

    • 参数一: 要渲染的内容, 可以是HTML元素, 也可以是React的组件
    • 参数二: 将渲染的内容, 挂载到哪一个HTML元素上
  • 我们可以通过 {} 语法来引入外部的变量或者表达式

  • 按钮发生点击

 <body>
    <div id="app">app</div>
    <!-- 使用jsx 并且希望script中的jsx代码被解析,必须在script标签中添加一个属性 -->
    <!-- jsx特点: 多个标签(组件) 在最外层(根)只能有一个标签 -->
    <script type="text/babel">
      // 1.渲染的内容
      // 2.挂载的对象
      let message = "Hello World";
      function btnClick() {
        message = "Hello React";
        console.log(message); // 数据改变了 但是没有重新渲染函数
        // 这样ui就会进行改变了
        render();
      }
      function render() {
        ReactDOM.render(
          <div>
            <h2>{message}</h2>
            <button onClick={btnClick}>修改文本</button>
          </div>,
          document.getElementById("app")
        );
      }
      // 默认要先执行一次render函数
      render();
    </script>
  </body>

react组件化开发

  • 整个逻辑可以看成一个整体,那么我们就可以将其封装成一个组件

    • ReactDOM.render 第一个参数式一个html元素或者一个组件

    • 所以我们可以先将之前的业务逻辑封装到一个组件中,然后传入到 ReactDOM.render 函数中的第一个参数

  • 这里暂时使用的方式封装组件:

    • 定义一个类 (类名大写, 组件的名称是必须大写的, 小写会被认为是HTML元素),继承自React.Component
    • 实现当前组件的render函数 render当中返回的 jsx 内容,就是之后React会帮助我们渲染的内容
//封装APP组件
class App extends React.Component  { 
     render(){   
        return (<div>hello</div>)
     }
}
// 渲染组件
ReactDOM.render(<App/>, document.getElementById ('app')
 <body>
    <div id="app">app</div>
    <!-- 使用jsx 并且希望script中的jsx代码被解析,必须在script标签中添加一个属性 -->
    <!-- jsx特点: 多个标签(组件) 在最外层(根)只能有一个标签 -->
    <script type="text/babel">
      // 封装一个组件
      // 函数式组件
      function App() {}
      // class 组件
      class App extends React.Component {
        // es6 类中定义属性
        constructor() {
          super(); // 初始化父类实例
          //   this.message = "Hello World"; / jsx 依赖了一个数据 并且当这个数据发生改变的时候,希望界面也发生改变
          // 不能定义在当前对象的里面 应该定义在state中
          this.state = {
            message: "Hello World",
          };
        }
        btnClick() { 
          this.setState({ // 内部会重新调用render函数
            message: "Hello React",
          });
          this.state.message = "hello React" // 不会更改 数据改变了 但是视图没有改变 因为没有调用render函数
          //   this.message = "Hello React"; // this is undefined 内部调用btnClick.apply(undefined,xxx)
        }
        render() { // render 不会手动调用 被 react 调用进行重新渲染
          return (
            <div>
              <h2>{this.state.message}</h2>
              <button onClick={this.btnClick.bind(this)}>改变文本</button>
            </div>
          );
        }
      }
      ReactDOM.render(<App />, document.getElementById("app"));
    </script>
  </body>

组件化-数据依赖

  • 在组件中的数据,我们可以分成两类:

    • 参与界面更新的数据:当数据变量时,需要更新组件渲染的内容
    • 不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容
  • 参与界面更新的数据,是定义在当前对象的 state 属性中

    • 我们通过在构造函数中: this.state = {定义的数据}

    • 当我们的数据发生变化时,我们调用 this.setState更新数据,并且通知React进行update操作

      • 在进行update操作时,就会重新调用render函数, 并且使用最新的数据,来渲染界面
class App extends React.Component  {
     constructor() {    
        super();
        //定义数据  
        this.state = {
            message: 'hello world'
        }         
     } 
     // 使用数据  
     render() {   
        return (  
           <div>    
             <h2>{this.state.message}</h2>
           </div>
         )
        }
}

组件化-事件绑定

  • React中事件绑定: 在标签中定义 on + 事件名

    • 例如: <button onClick={this.changeText}>改变文本</button>
  • 当前这个函数的this指向的是谁呢?

    • 默认情况下是 undefined
    • 这次因为React并不是直接渲染成真实的DOM, 我们所编写的button只是一个语法糖, 它的本质React的Element对象
    • 那么在这里发生监听的时候,react给我们的函数绑定的this默认情况下就是一个undefined
  • 我们在绑定的函数中,可能想要使用当前对象,比如执行 this.setState 函数,就必须拿到当前对象的this

    • 我们就需要在调用函数时,给这个函数直接绑定this
    • <button onClick={this.changeText.bind(this)}>改变文本</button>