初识React,回顾JS基础

88 阅读5分钟

用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"));

这时我们点击按钮,发现并没有任何反应

+1无反应

这说明,React不会根据你对n进行的操作而自动帮你刷新视图,它不会监听和劫持任何东西

所以应该咋办呢?我们需要自己去刷新,于是我们在箭头函数里添加如下内容

onClick: () => {
        n += 1;
        ReactDOM.render(App, document.querySelector("#app")); 
      }

但这样仍是不行,

为什么?

因为我们在写出const App = React.createElement(...)的时候,App就已经计算出它里面的子元素n0,所以当第二次渲染的时候,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

+1有反应

插播:回忆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-loaderbabel-loader取代了
  • babel-loaderwebpack内置了(所以,如果你是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是自由自在