第一次学习 React

Rinsann 2021年10月13日 471次浏览

React 初识

引入React,引入React有两种方式

从CDN引入React

CDN引入(需注意顺序)

引入React:https://cdn.bootcss.com/react/16.10.2/umd/react.development.js

引入ReactDOM:https://cdn.bootcss.com/react-dom/16.10.2/umd/react-dom.development.js

cjs和umd的区别

  • cjs全程CommonJS,是Node.js支持的模块规范
  • umd是统一模块定义,兼容各种模块规范(含浏览器)
  • 理论上是有限使用umd,同时支持Node.js和浏览器
  • 最新的模块规范是使用import 和 export关键字

通过webpack引入React

import ... from ...

  • yarn add react react-dom
  • import React from ‘react’
  • import ReactDOM from ‘react-dom’
  • 可 使用 create-reacte-app 代替
  • 安装 yarn global add create-react-app,创建目录 create-react-app 项目名、进入目录,运行yarn start

其他

  • 除webpack外,rollup、parcel也支持上面写法

新手使用create-react-app,老手用webpack/rollup

//用React实现+1
const React = window.React;
const ReactDOM = window.ReactDOM;
const root = document.querySelector("#root");
let n = 0;
// const App = React.createElement("div",{...},...)  失败实例,因为react不会帮我们刷新, ()=> 加一个函数。函数执行时遇到外部变量会去读最新值
const App = () =>
  React.createElement("div", { className: "red" }, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
          ReactDOM.render(App(), root);
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(App(), root);

对比普通代码与函数

普通代码

  • let b= 1+a

这是函数

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

区别

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

对比React元素和函数组件

对比

  • App1 = React.createElement(‘div’,null,n),App1 是一个React元素
  • App2 = () => React.createElement(‘div’,null,0),App2是一个React 函数组件

函数App2是延迟执行的代码,会在被调用的时候执行

这里是指代码执行的时机,不是同步或异步,同步或异步关注的是得到结果的时机

React元素

  • createElement 的返回值 element 可以代表一个div
  • 但element并不是真正的div(DOM对象),所以我们一般称element为虚拟DOM对象

() => React元素

  • 返回 element 的函数,也可以代表一个div,这个函数可以多次执行,每次得到最新的虚拟div
  • React 会对比两个虚拟div,找出不同(DOM Diff算法),局部更新视图

JSX

x表示扩展,所以JSX就是JS扩展版

Vue中有 vue-loader

.vue 文件里写<template><script><style>,通过vue-loader变成一个构造选项

React有JSX

把<button onClick="add">+1</button> 变成 React.createElement(‘button’,{onClick:...},’+1’)
这其中用到了编译原理,以前jsx-loader就可以做到这些, 后来 jsx-loader 被 babel-loader替代,而babel-loader 被 webpack内置了。

使用JSX

方法一:CDN

  1. 引入babel.min.js,把

    <script>改成<script type="text/babel">
    
  2. babel会自动进行转译吗,这种方法似乎并不支持src

  3. 生产环境不要使用,它要下载一个babel.min.js 还要在浏览器端把JSX翻译成JS,效率太低

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>
    <script src="https://cdn.bootcss.com/react/16.10.2/umd/react.development.js"></script>
    <script src="https://cdn.bootcss.com/react-dom/16.10.2/umd/react-dom.development.js"></script>
    <script src="https://cdn.bootcss.com/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
    <script type="text/babel">
      let n = 0;
      const App = () => (
        <div>
          {n}
          <button
            onClick={() => {
              n += 1;
              render();
            }}
          >
            +1
          </button>
        </div>
      );
      const render = () =>
        ReactDOM.render(<App />, document.querySelector("#app"));
      render();
    </script>
  </body>
</html>

console.log(window.React);
console.log(window.React.createElement);
console.log(window.ReactDOM);
console.log(window.ReactDOM.render);

const React = window.React;
const ReactDOM = window.ReactDOM;

let n = 0;
const App = () =>
  React.createElement("div", null, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
          console.log(n); 
          ReactDOM.render(App(), document.querySelector("#app")); // 为什么还是不能重新渲染
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(App(), document.querySelector("#app"));

方法二:使用create-react-app

  • 跟@vue/cli用法类似
  • 全局安装yarn global add create-react-app,初始化目录 create-react-app react-demo-1
  • 进入目录 cd react-demo-1 开始开发 yarn start
  • 看看App.js ,webpack让js默认走babel-loader

使用JSX注意事项

不能使用class 必须使用className

<div className="red">n</div> 被转译为 React.createElement('div',{className:'red'},"n")

插入变量

  • 标签里面的所有JS代码都要用 {} 包起来,如果需要变量n,那么就用 {} 把n 包起来
  • 如果需要对象,那么就要用 {} 把对象包起来,如 {{name:’frank’}}

习惯在 return 后面加 ()

JSX中的条件判断

在Vue里

<template>
	<div>
		<div v-if="n%2===0"></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>
    )
}

// 还可以写成
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} </>
    )
    return content
}

循环语句

在Vue里可以遍历数组和对象

<template>
    <div>
    	<div v-for="(n,index) in numbers" :key="index">
            下标 {{index}}, 值为 {{n}}
        </div>
    </div>
</template>

在React里

const Component = (props) => {
	reruen props.numbers.map((n,index)=>{return <div>下标{index} 值为{n} </div>})
}
// 如果需要外面的div 可以写成
const Componenet = (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 的区别在于你是愿意用Vue封装好的v-*还是愿意在React里写原生JS