使用引进cdn的方式引入react(此种方式只用来演示,实际项目中基本不会使用cdn方式引入)
我们使用bootcdn网址获得react cdn网址;
parcel index.html命令启动的项目;
查看react 与 react-dom
我们在main.js可打印出console.log(window.React); console.log(window.ReactDom);
使用react的第二种方式,使用webpack配置,在这里我们就直接使用create-react-app,可快速安装开发react项目所用的依赖包;
npx create-react-app my-app 安装成功!yarn start
分析react项目结构
使用两种方式实现点击按钮数字自增的效果
使用引进cdn react方式
const React = window.React; // React对象
const ReactDOM = window.ReactDOM; // ReactDOM对象
const root = document.querySelector('#app');
let n = 0;
// 使用React.createElement创建元素,createElement()有三个参数,第一个参数标签名字,第二个参数属性键值对象,第三个标签内容
const App = React.createElement('div',{className:"red"},[
n,
React.createElement('button', {
onClick: ()=> {
n += 1;
}
}, "+1")
])
ReactDOM.render(App, root);
这就形成了react的2个概念,React 元素和函数组件
const app1 = React.createElement('div',null,'app1');
app1是React 元素,会立即执行(名字小写,约定俗称);
const App2 =()=> React.createElement('div',null,'app1');
App2是函数组件,被调用的时候再执行(名字大写,约定俗称);
需要注意的是App1元素代表DOM对象,不是真正的DOM对象,是虚拟DOM对象;函数组件虽然不是元素但是返回的是元素,可以函数组件也可以代表DOM对象,这个函数可以多次执行,每次执行会得到最新的虚拟DOM对象;第一次的虚拟DOM对象与第二次不一样,是需要更新页面,React会对比两个虚拟DOM对象,找出不同,局部更新视图,这大大提高了渲染性能,找不同的算法叫做DOM Diff算法;
看到以上代码,你肯定感觉react太弱了,写法太复杂了,完全没有办法和vue相比呀,其实上面的代码是react最弱的用法,后面会慢慢增加更多的用法,上面的例子只是用来让我们来理解react运行的原理,在实际项目中基本上不会这样使用,而是使用工程项目的方式;
JSX登场了!X代表扩展的意思,意思是JS的扩展版;
vue有vue-loader可以吧vue单文件里面的template、script、style标签变成一个构造选项;在写法上,react有jsx,那这JSX怎么变成React可以识别的代码,这也需要一个loader,不是jsx-loader,而是babel-loader,因为babel-loader已经取代了jsx-loader的功能,而babel-loader又被webpack内置,所以只要你使用webpack来构建项目,就不需要另外安装loader;
JSX写法
<button onClick="add">+1</button>
经过loader编译后的代码
React.createElement('button',{"onClick":()=>{add()},"+1")
现在让我们试用一下JSX,就在我们刚才启动的本地项目里,babel-loader也可以使用cdn方式引入;代码如下
let n = 0;
const App = ()=> (
<div>
{n}
<button
onClick={()=>{
n += 1;
render()
}}
>+1</button>
</div>
)
const render = () => (ReactDOM.render(<App/>, document.querySelector("#app")));
render()
JSX写法总结就是:标签按照html标签的写法,js变量与方法都使用{}花括号包起来;
注意:永远不要在生成环境使用cdn方式引进babel-loader,因为这样效率太低了,因为在客户端,babel要先编译浏览器才能识别代码,那为什么不先在我们本地编译完成,让客户端直接使用呢?这使用我们之前使用create-react-app命令启动的my-app项目,就可以实现;
使用项目工程方式实现点击按钮自增1的效果
删除项目现在不需要的文件
index.js代码如下
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app.js'
ReactDOM.render(
<App/>,
document.getElementById('root')
);
新建一个app.js,代码如下
import React from 'react'
const app = ()=>{
return (
<div>
你好呀,我是app组件
</div>
)
}
export default app;
页面展示为
如何在jsx里面使用条件判断
第一种写法:
import React from 'react'
let n = 2;
// 条件判断,写法一
const app = ()=>{
return n%2 === 0 ? <div>我是偶数</div> : <div>我是奇数</div>
}
export default app;
第二种:
import React from 'react'
let n = 2;
// 条件判断,写法一
const app = ()=>{
return (
n%2 === 0 ? <div>我是偶数--第二种方式</div> : <div>我是奇数--第二种方式</div>
)
}
export default app;
第三种:
import React from 'react'
let n = 2;
// 条件判断,写法三
const app = ()=>{
const nText = n%2 === 0 ? '我是偶数--第三种方式' : '我是奇数--第三种方式';
return <div>{nText}</div>
}
export default app;
可以看出react写法比较自由,没有固定的形式,只要记住两点:在标签里面使用变量和方法要使用花括号包起来;
如何在jsx里面使用循环
react中的组件
到底什么是组件?
能和其他物件组合起来的物件就是组件;组件并没有明确的定义,靠感觉就可以;就目前而言,一个返回React元素的函数就是组件;在vue中,一个构造选项就可以是一个组件;
React中有两种组件:一是:函数组件;二是:类组件
函数组件
function Dog(props){
return <div>dog是忠实的动物!它的名字是:{props.name}</div>
}
// 使用方法:
<Dog name="Alice"/>
类组件
class Dog extend React.Component {
render(){
return <div>dog是忠实的动物!它的名字是:{this.props.name}</div>
}
}
// 使用方法:
<Dog name="Alice"/>
需要注意的是:当我们在jsx里面使用标签时,要时刻记住所写的标签不是html标签,所写的标签会被翻译成React.createElement()
React.createElement的逻辑
第一种情况:直接使用原生标签,在babel编译时会编译成React.createElement('div'...),此时属于传给函数字符串'div',则会创建一个div;
const app = ()=>{
return <div>我是直接使用div</div>
}
export default app;
第二种情况:使用函数组件,比如以下loop,在babel编译时会编译成React.createElement(loop),此时属于传给createElement一个函数,则会调用该函数,获取其返回值;
// 循环测试
const app = ()=>{
return <div><Loop numbers={numbers}/></div>
}
const loop = (props)=>{
return <div>{props.numbers}</div>
}
export default app;
第二种情况:使用类组件,比如以下Dog,在babel编译时会编译成React.createElement(loop),此时属于传给createElement一个类,则在类前面加个new(会执行constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值;
class Dog extend React.Component {
render(){
return <div>dog是忠实的动物!它的名字是:{this.props.name}</div>
}
}
你可以到babel online来验证以上内容!
使用react实现点击按钮增加1的效果
app.js代码
import React from 'react'
import Son from './son.js'
import './style.css'
const app = ()=>{
return (<div className='bagRed'>
我是父元素
<Son name='儿子'/>
</div>)
}
export default app;
son.js代码,此组件是函数组件,变量的声明、读取与设置要使用const [n,setN] = React.useState(0);以下方式;
import React from 'react';
import SonChild from './sonChild'
const Son = (props)=>{
const [n,setN] = React.useState(0);
return (
<div className='sonBag'>
我是{props.name}我的初始值是{n}<button onClick={()=>setN(n+1)}>+1</button>
<SonChild name='孙子'/>
</div>
)
}
export default Son;
sonChild.js代码如下,此组件是类组件,变量的声明、读取与设置要使用this.state = { n:0 }
this.props.name this.setState({n:this.state.n+1})
import React from 'react';
class SonChild extends React.Component {
constructor(){
super();
// 初始化
this.state = {
n:0
}
}
add(){
this.setState({n:this.state.n+1})
}
render(){
return(
<div className='sonChildBag'>我是{this.props.name},我的初始值是{this.state.n}<button onClick={()=>this.add()}>+1</button></div>
)
}
}
export default SonChild;