React(一)-安装,顶层API,JSX

337 阅读6分钟

一、写在前面

React在我现在看来,提供给用户的 API 没有 Vue 提供的多,那么它是怎么并称三大框架的呢?带着这个问题学习。

二、安装 React

方法一、CDN引入

 <!-- ... 其它 HTML ... -->
 
 <div id="like_button_container"></div>

 <!-- ... 其它 HTML ... -->

  <!-- 加载 React。-->
  <!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

  <!-- 加载我们的 React 组件。-->
  <script src="like_button.js"></script>

</body>

like_button.js 就是我们的 React 代码

方法二、包引入

yarn add react react-dom
import React from 'react'
import ReactDOM from 'react dom'

方法三、create-react-app

和使用 Vue-cli 一样

三、React 初体验

以下代码使用 CDN 引入,在使用 create-react-app 时默认js文件为 jsx 文件所以会报错,当前我们暂时使用 CDN 

我们先不用管 jsx 是什么,下面这段代码完全是js代码外加两个 React API,我们想要实现一个按钮点击后旁边的数字加一

//index.js

let n = 0;
const root = document.querySelector("#root");
const App = 
  React.createElement("div", { className: "red" }, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(APP, root);

现在的 button 点击后并不能加一,因为并没有重新渲染。接下来我们解决这个问题。

四、实现加一按钮

在实现按钮之前我们先回顾一下代码,我们添加一行代码看看能不能实现按钮

let n = 0;
const root = document.querySelector("#root");
const App = 
  React.createElement("div", { className: "red" }, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
          ReactDOM.render(APP, root);
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(APP, root);

我们在创建App时,n 已经赋值了,即使之后再改变 n 不会再改变的,之后 n 再怎么变和App都没有关系了,所以我们即使每次点击都重新渲染App都不会更新。

所以我们需要App重新赋值,重新取n的值。

let n = 0;
const root = document.querySelector("#root");
const App = () =>
  React.createElement("div", { className: "red" }, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
          ReactDOM.render(APP(), root);
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(APP(), root);

把App变成函数,每次渲染我们重新调用App都会取到最新的n。

对比App是变量,App只会赋值一次,多次渲染也不会改变n

五、函数与变量

let i;
for (i = 0; i < 0; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000);
}

打出6个6, setTimeout里的函数每次回调时,都会取到最新值

let i;
for (i = 0; i < 0; i++) {
  let j = i;
  setTimeout(() => {
    console.log(j);
  }, 1000);
}

变量j只会赋值一次

let b = 1 + a

let f = ()=>1 +a
let b = f()

普通代码立即求值,读取a的当前值,函数会等调用时再求值,即延迟求值。且求值时才会读 取a的最新值 ,你想求值时调用函数即可。

App1 = React.createElement('div', null, n)
App1是一个React元素
App2 =()=>React.createElement('div', nul1, n)
App2是一个React函数组件

n变化了调用一次函数即可更新到视图

六、createElement()

React.createElement(
  type,
  [props],
  [...children]
)

创建并返回指定类型的新 React 元素。与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。我们一般称为虚拟DOM

  • type:标签名或 React 组件或是 React fragment 类型。
  • props:被创建 React 元素的属性
  • children:子标签或子组件

如果我们像上面代码一样,每次点击都执行一次 createElement() ,都会得到一个新的虚拟 DOM 对象,React会对比两个虚拟div,找出不同,局部更新视图(diff 算法) 

七、Diff算法 和 Vue 的比较

react和vue的虚拟dom都是一样的, 都是用JS对象来模拟真实DOM,然后用虚拟DOM的diff来最小化更新真实DOM。

除了极个别实现外,两者前半部分(用JS对象来模拟真实DOM)几乎是一样的。

而对于后半部分(用虚拟DOM的diff来最小化更新真实DOM)两者算法也是类似的,包括replace delete insert等

虽然两者对于dom的更新策略不太一样, react采用自顶向下的全量diff,vue是局部订阅的模式。 但是这其实和虚拟dom并无关系

八、JSX(React的模板语法)

考虑如下变量声明:

const element = <h1>Hello, world!</h1>;

JSX,是一个 JavaScript 的语法扩展。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2user.firstNameformatName(user) 都是有效的 JavaScript 表达式。

JSX被整合到 babel 中,CDN引入 babel 即可,或者webpack自动使用babel。

每个 JSX 元素都是调用 React.createElement() 的语法糖。一般来说,如果你使用了 JSX,就不再需要调用该方法。

为了便于阅读,我们会将 JSX 拆分为多行。同时,我们建议将内容包裹在括号中,虽然这样做不是强制要求的,但是这可以避免遇到自动插入分号陷阱。

现在我们的代码

let n = 0;
const root = document.querySelector("#root");
const App = () => (
  <div>
    {n}
    <button
      onClick={() => {
        n += 1;
        render();
      }}
    >
      +1
    </button>
  </div>
);

let render = () => ReactDOM.render(<App />, root);
render();

create-react-app 默认使用JSX(即JSX函数调用返回的是一个React对象),所以不会使用jsx后缀,使用js后缀即可。

render里的<App/>之后会说,现在把它理解成函数调用即可。

九、JSX里的js语句

const Component = ()=>{
    return n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span>
}

const Component = () => {
    return (
        <div>
           {n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span> }
        </div>

代码里的<div>n是偶数</div>是 JSX 可以生成 React “元素”,如果没有{}那么下面这段代码意味着字符串。还可以这样写:

const Component = () => {
  const inner = n % 2 === 0 ? <div>n是偶数</div> : <span>n是奇数</span>;
    return <div>{inner}</div>;
};

比Vue自由

JSX的循环语法

const Component = (props) => {
    return props.numbers.map((n,index)=>{
        return <div>{index} value {n} </div>
    });
};

<Component name={1,2,3}/>

十、使用JSX的注意事项

  •  <div = className"red">n</div> 被转译为 React.createElement('div',{ className :'red'},"n") 
  • 插入变量,标签里面的所有JS代码都要用{}抱起来 如果你需要变量n,那么就用{}把n包起来 如果你需要对象,那么就要用{}把对象包起来,如 { {name:'frank'}} 
  • 习惯return后面加() 
  • 组件必须返回一个 React 对象,React 对象里想使用js代码加中括号
  • JSX就是JS语言扩展,加了XML标签来代表React元素