一、写在前面
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 + 2,user.firstName 或 formatName(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元素