用React 实现+1操作
如下代码,我们想要用React实现一个简单的按钮+1操作
let n = 0;
const App = React.createElement("div", null, [
n,
React.createElement(
"button",
{
onClick: () => {
n += 1;
}
},
"+1"
)
]);
ReactDOM.render(App, document.querySelector("#app"));
这时我们点击按钮,发现并没有任何反应
这说明,React不会根据你对n进行的操作而自动帮你刷新视图,它不会监听和劫持任何东西
所以应该咋办呢?我们需要自己去刷新,于是我们在箭头函数里添加如下内容
onClick: () => {
n += 1;
ReactDOM.render(App, document.querySelector("#app"));
}
但这样仍是不行,
为什么?
因为我们在写出const App = React.createElement(...)的时候,App就已经计算出它里面的子元素n是0,所以当第二次渲染的时候,App里的子元素仍然是0,已经与n无关了。
简单来说,const App = React.createElement(...)这段代码,只会执行一次,再之后,n再怎么变,都与App无关了
所以,我们需要让App重新执行,再去取一遍n的值,做出如下更改
const App =()=> React.createElement(...)
有何区别?
- 之前的
App等于一个表示div的对象 - 现在
App等于一个函数,这个函数执行之后,才会返回对象 - 这么一来
App必须执行了,才会去取n的值
于是我们再把两行ReactDOM.render(App,document.querySelector("#app"));里的App更改为App()(去renderApp返回的div)
因为函数在运行的时候会去重新读n的值,这就导致我可以得到最新的n
插播:回忆6个6
上述的例子,很容易联想到经典考题 6个6
let i
for(i=0;i<6;i++){
setTimeout(()=>{
console.log(i)
},1000)
}
一秒钟之后,会打出6个6,因为函数里面的变量只会在它执行的时候去计算,for循序结束(i从0变成6)之前,函数根本不会去看它里面的变量是多少
那么怎么让它打印出0到5呢
let i
for(i=0;i<6;i++){
let j = i
setTimeout(()=>{
console.log(j)
},1000)
}
因为let j = i的作用域是整个for循环,每一次执行循环都会进入到一个新的作用域(第一次i=0,第二次i=1...),所以每一次的循环的j都会被赋值成不同的i
但由于仍然有很多新人难以理解,所以JS为上述代码提供了一个语法糖
for(let i=0;i<6;i++){
setTimeout(()=>{
console.log(i)
},1000)
}
这么一来,就能打出0到5
小感想
通过上面的例子,我们很容易发现React和Vue的不同,React十分考验我们的JS基础知识
小结
目前我们知道
React元素
createElement的返回值element可以代表一个div- 但是
element只是代表div,它并不是一个真正的div(DOM对象) - 也就是说,不能把这个
element直接插入到页面里面 - 所以我们一般称
element为虚拟DOM对象
()=>React元素
- 它是一个返回
element的函数,这个element可以代表一个div - 这个函数可以
多次执行,每次得到最新的虚拟div - React会对比两个虚拟div,
找出不同,局部更新视图 找出不同的算法叫做DOM Diff算法
JSX
但目前来看,React的代码过于冗长不够美观,于是,为了弥补这个问题,发明了一个语言——JSX
简单回忆一个Vue,
- Vue有
vue-loader .vue文件里面写<template><script><style>- 通过
vue-loader变成一个构造选项
而React有JSX
- 那是不是React用了
jsx-loader? - 并不准确,实际上
jsx-loader被babel-loader取代了 - 而
babel-loader被webpack内置了(所以,如果你是React的开发者,你不用装任何东西,就能愉快的开发了)
于是乎,上面的+1代码就变成了
let n = 0;
const App = () => (
<div>
{n}
<button
onClick={() => {
n += 1;
render();
}}
>
+1
</button>
</div>
);
const render = () =>
ReactDOM.render(<App />, document.querySelector("#app"));
render();
这里的<div>的意思,就是React.createElement('div'),而变量和函数都用{}包起来就完事了
使用JSX的注意事项
-
注意不能用
class,要用className<div className="red">n</div>被译为React.createElement('div',{classNme:'red'},"n")
-
插入变量时
标签里所有JS代码都要用{}包起来- 如果需要变量n,那么就用
{}把n包起来 - 如果需要对象,就用
{}把对象包起来,如{{name:'Jack'}}
-
习惯return后面加
(),- 因为不加相当于
return undefined
- 因为不加相当于
在JSX里面使用if...else
条件判断,如果是在Vue里
<template>
<div>
<div v-if="n%2===0">n是偶数</div>
<span v-else>n是奇数</span>
</div>
</template>
而在React里
const Component = () =>{
return n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span>
}
//如果需要外面的div,可以写成
const Component = () =>{
return(
<div>
{ n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span> }
</div>
)
}
可以看出React十分像在写JS
还可以写成这样
const Component = () =>{
const content = (
<div>
{ n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span> }
</div>
)
return content
}
还还可以这样写
const Component = () =>{
const inner = n%2===0 ? <div>n是偶数</div> : <span>n是奇数</span>
const content = (
<div>
{inner}
</div>
)
return content
}
还还还可以这样写
const Component = () => {
let inner
if (n%2===0) {
inner = <div>n是偶数</div>
} else {
inner = <span>n是奇数</span>
}
const content = (
<div>
{ inner }
</div>
)
return content
}
在JSX写循环语句
同样对比Vue,在Vue里面可以遍历数组和对象
<template>
<div>
<div v-for="(n, index) in numbers"
:key="index">
下标{{index}},值为{{n}}
</div>
</div>
</template>
而在React里面
const Component = (props) => {
return props.numbers.map((n,index)=>{
return <div>下标{index} 值为{n}</div>
})
}
//同样,如果需要外面的div,可以写成
const Component = (props) => {
return (<div>
{props.numbers.map((n,index)=>{
return <div>下标{index} 值为{n}</div>
})}
</div>)
}
还可以这样写
const Component = (props) => {
const array = []
for(let i=0;i<props.numbers.length;i++){
array.push(<div>下标{i}值为
{props.numbers[i]}</div>)
}
return <div>{ array }</div>
}
结论
- 在Vue里面,只能用Vue提供的语法写条件判断,循环
- 在React里面,你爱咋写咋写,说白了你就是在写JS而已
- Vue是舒服爽快,React是自由自在