1.使用React渲染一个最基本的页面
//1.导入
import React from "react";//创建组件、虚拟DOM元素,生命周期
import ReactDOM from 'react-dom';//把创建好的组件和虚拟DOM放到页面上去展示的
//2.创建虚拟DOM元素
//参数1:创建的元素的类型
//参数2:是一个对象或null,表示当前这个DOM元素的属性
//参数3:子节点
//参数n:其他子节点
const myh1 = React.createElement('h1',{id:'myh1',title:'this is myh1'},'这是用react创建的');
//3,使用ReactDOM把虚拟DOM渲染到页面上
//参数1:要渲染的那个虚拟DOM元素
//参数2:页面上的一个容器
ReactDOM.render(myh1,document.getElementById('container'));
2.实现DOM元素嵌套渲染
const myh1 = React.createElement('h1',{id:'myh1',title:'this is myh1'},'这是用react创建的');
const mydiv = React.createElement('div',{id:'mydiv',title:'this is mydiv'},'这是用react创建的div',myh1);
ReactDOM.render(mydiv,document.getElementById('container'));
3.JSX语法
启用JSX语法
(1)安装babel插件,执行以下命令
cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
cnpm babel-preset-env babel-preset-stage-0 babel-preset-react -D
(2)在webpack.config.js文件中写入第三方配置规则
//webpack默认只能打包处理.js后缀名类型的文件,像.png,.vue等无法处理,所以要配置第三方的loader
module.exports = {
mode:"development",
plugins:[
htmlPlugin
],
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
//千万别忘记添加exculde排除项
{test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/,}
]
}
}
(3)在项目根目录下添加.babelrc
配置文件,写入以下代码
{
"presets":["env","stage-0","react"],
"plugins":["transform-runtime"]
}
JSX语法的本质:
并不是直接把JSX渲染到页面上,而是内部先转换成立creatElement形式后再渲染的
在JSX中可以混合写入JS表达式,但是要把JS代码写到{}中
let a = -2;
let str = '你好';
let boo = true;
let title = '999';
const h1=<h1>这是h1</h1>
const arr = [
<h2>这是h2</h2>,
<h3>这是h3</h3>
.]
ReactDOM.render(<div>
//渲染数字
{a+2}
//渲染字符串
{str}
//渲染布尔值
{boo ? '条件为真':'条件为假'}
//为属性绑定值
<div title = {title}></div>
//渲染JSX元素
{h1}
//渲染JSX数组
{arr}
</div>,
document.getElementById('container')
)
将普通字符串转为JSX数组并渲染到页面上
(1)在外部使用forEach循环
const arr = ['小王','小路','小刘','小样'];
const newArr=[];
arr.forEach(item => {
newArr.push(<h3>{item}</h3>);
});
ReactDOM.render(
<div>
{newArr}
</div>,
container
)
(2)在渲染内部使用map函数(推荐)
const arr = ['小王','小路','小刘','小样'];
ReactDOM.render(
<div>
{arr.map(item=><h3>{item}</h3>)}
</div>,
container
)
注意:1.Reac中用className代替class,用htmlFor代替for循环
2、在JSX创建DOM的时候,所有的节点,必须由唯一的根元素进行包裹
3、在JSX语法中,标签必须成对出现,如果是单标签,则必须自闭和
React中创建组件的两种方式
注意:组件名称首字母必须大写
第一种 使用构造函数来构建组件
function Hello() {
//在组件中必须返回一个合法的JSX虚拟DOM元素
return <h1>这是hello组件</h1>
}
ReactDOM.render(
<div>
{/*直接把组件的名称,以标签的形式丢到页面上即可*/}
<Hello />
</div>,
container
)
第二种 使用class创建组件
最基本的组件结构
//如果要使用class定义组件,必须让自己的组件继承自React.Component
class Hello extends React.Component {
//在组件内部,必须有render函数
render(){
//render函数中,必须返回合法的JSX虚拟DOM结构
return <div><h1>这是class创建的组件</h1></div>
}
}
在class关键字创建的组件中,如果想使用外界传递过来的props参数,不需要接收,直接通过this.props.xxx访问
class People extends React.Component{
render(){
//在class组件内部,this表示当前组件的实例对象
return <h1>{this.props.name}---{this.props.age}</h1>
}
}
var user = {
name : 'yang',
age : 18
}
ReactDOM.render(
<div>
<People {...user}></People>
</div>,
document.getElementById('container')
);
使用class创建类
注意:在class的{}内只能写构造器,静态方法和静态属性,实例方法
class Hello {
//这是类的构造器,每一个类都有一个构造器,如果没有手动指定,,认为类内部有一个隐形的空构造器
//构造器的作用就是,每当new这个类的时候,必然会优先执行构造器中的代码
constructor(name,age){
//实例属性(通过new出来的实例访问到的属性)
this.name = name;
this.age = age;
}
//在class内部听过static修饰的属性,为静态属性(直接通过构造函数进行访问)
static info = 'eee';
//这是Hello的实例方法,挂载到原型对象上
say(){};
//这是静态方法
static show(){}
}
使用extends实现子类继承父类
//这是父类
class People{
constructor(name,age){
this.name = name;
this.age = age
}
}
//这是子类 美国人
//在class类中,可以使用extends关键字实现子类继承父类
class American extends People{
}
constructor构造器中super函数的使用
//这是父类
class People{
constructor(name,age){
this.name = name;
this.age = age
}
}
//这是子类 美国人
//在class类中,可以使用extends关键字实现子类继承父类
class American extends People{
constructor(name,age){
//如果一个子类通过extends关键字继承了父类,那么在子类的constructor构造函数中,必须优先调用一下super()
//super是一个函数,其实就是父类中constructor构造器的一个引用
//必须传递参数
super(name,age)
}
}
将组件抽离为单独的JSX文件
(1)在src代码源文件下新建一个名为components的文件夹存放组件
(2)每一个组件都是一个后缀名为.jsx的文件
(3)每个组件前面必须引入React包,最后在文件内需要把组件导出(export default)
(4)需要使用此插件时需要导入(例:import Hello from ‘路径名’)
配置webpack从而在导入文件时可以省略.jsx后缀名
配置webpack设置根目录
在webpack.config.js中写入如下代码
resolve:{
extensions:['.js','.jsx','.json'],//表示这几个文件的而后缀名可以不写,自动补全
alias:{//表示别名
'@':path.join(__dirname,'./src')//这样,@就表示项目根目录src这一层路径
}
}
两种创建组件方式对比
注意:1.使用class关键字创建的组件,叫“有状态组件”,有自己的私有数据(this.state)和生命周期函数,
——如果一个组件需要有自己的私有数据,则推荐使用class创建的组件
2.使用function创建的组件,叫“无状态组件”,只有props,没有自己的私有数据和生命周期函数
——如果一个组件不需要有私有的数据,则推荐使用无状态组件
3.props中的数据都是外界传递过来的,都是只读的,不能重新赋值
state中的数据都是组件私有的(通过AJAX获取回来的数据,一般是私有数据),都是可读可写的
再组件中使用样式
行内样式:
在这里插入代码片
<h1 style={{margin:'0 auto',color:'red'}}>刚睡醒</h1>//字符串形式的值必须带引号
样式封装:
const styles = {
itemStyle : {border:'1px dashed #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'},
userStyle : {fontSize:'14px'},
contentStyle : {fontSize:'12px'}
}
function CmtItem(props){
return <div style={styles.itemStyle}>
<h1 style = {styles.userStyle}>评论人:{props.user}</h1>
<p style={styles.contentStyle}>评论内容:{props.content}</p>
</div>
}
将样式表抽离为单独的JS文件
在webpack中不支持识别css文件,所以要执行以下命令
(1)下载包
cnpm install style-loader css-loader -D
(2)在webpack.config.js文件中配置环境
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
//千万别忘记添加exculde排除项
{test: /\.js|jsx$/, use:'babel-loader', exclude:/node_modules/,},
{test:/\.css$/,use:['style-loader','css-loader']},//打包处理CSS样式表的第三方loader
]
},
注意:在组件中直接导入CSS样式表,默认是在全局上,整个项目都会生效
解决方法:为样式表通过modules参数启用模块化
**css模块化只针对类选择器和ID选择器生效,不会对标签选择器模块化
**
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
//千万别忘记添加exculde排除项
{test: /\.js|jsx$/, use:'babel-loader', exclude:/node_modules/,},
{test:/\.css$/,use:['style-loader','css-loader?modules']},//在css-loader后通过?追加参数modules,则是为CSS样式表启用模块化
]
},
如何引用
import cssObj from '@/components/CmtList.css';//title="_2KMjyWWi8Ngzkw70VqnVTm"(随机生成乱码,模块化)
<h1 className={cssObj.title}>这是评论列表组件</h1>
可以使用localIdentName自定义生成的类名格式
{test:/\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path]']}
可选的参数:
(1)[path]:表示样式表相对于项目根目录所在路劲
(2)[name]表示样式表文件名称
(3)[local]表示样式的类名定义名称
(3)[hash:length]表示32位的hash值,length可以指定长度
可以这样写{test:/\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']}
t通过local和global设置类名是否被模块化
被:global()包裹起来的类名不会被模块化,属于全局
:global(.test){
font-size: 120px;
color: aqua;
}
被:local()包裹起来的类名单独指定被模块化
:local(.test){
font-size: 120px;
color: aqua;
}
在项目中,自己写的样式表一般以.scss或.less为后缀,而第三方的样式表一般以.css为后缀名,所以我们只为.scss或.less文件启用模块化,这样引用第三方样式表(如bootstrap)就使用起来比较方便简单
(1)先装sass的包
cnpm install sass-loader node-sass -D
(2)再配置环境
{test:/\.scss$/,use:['style-loader','css-loader?modules&localIdentName=[path]','sass-loader']}//打包处理.scss文件的loader
第三方样式表就可以这样引入
<button className="btn btn-primary">按钮</button>
React中绑定事件
——在React中有一套自己的事件绑定机制,事件名为小驼峰命名
——为事件绑定处理函数的格式onClick={function(){ }}
——也可以将函数抽离出来
render(){
return <div>
今天学到了不少东西,
<hr/>,
{/* 注意这里后面不能加() */}
<button onClick={this.myhandle}>按钮</button>
{/*如果是箭头函数后面要加()*/}
<button onClick={()=>{this.myhandle()}}>按钮</button>
</div>
}
//这是一个实例方法
myhandle(){
console.log('你好');
}
规范写法
import React from 'react';
export default class BindEvent extends React.Component{
constructor(){
super();
this.state={};
}
render(){
return <div>
<h1>马上要走了</h1>
<hr/>
<button onClick={()=>{this.myHandle('啊哈是')}}>按钮</button>
</div>
}
myHandle= (item)=>{
console.log('show方法'+item);
}
}
使用this.setState修改state的数据
——在React中,如果想为state中的数据重新赋值,不要使用this.state=xxx;应该调用React提供的以下方法
this.setState({
name:'zhang'
})
React组件生命周期
组件的生命周期可分成三个状态:
(1)Mounting:已插入真实 DOM
(2)Updating:正在被重新渲染
(3)Unmounting:已移出真实 DOM
生命周期的方法有:
(1)componentWillMount 在渲染前调用,在客户端也在服务端。在组件挂载到页面前执行
(2)componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
(3)componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
(4)shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
(5)componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
(6)componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
(7)componentWillUnmount在组件从 DOM 中移除之前立刻被调用。
生命周期应用场景
(1)shouldComponentUpdate()函数用于性能优化
(2)在componentDidMount()函数里发送AJAX请求
使用create-react-app组件创建一个项目
(1)安装create-react-app
npm install create-react-app -g
(2)创建一个项目
create-react-app 项目名
(3)启动项目
npm run start
//或者 yarn start