React基础
脚手架安装
npm install create-react-app
安装完成以后,在控制台输入如下命令,验证是否安装成功
create-react-app --version
脚手架创建项目
create-react-app 项目名称
脚手架项目结果
1.
public是公开文件夹
2.
src目录是开发目录
- index.js是整个程序的启动目录,也是webpack的入口文件
- index.css是程序程序的公共CSS文件,如果需要写公共CSS文件最好写在这里
- App.js是根组件,在React里面,这就是一个根组件,React的组件是以JS文件的形式存在
- App.css是App.js组件的样式,一般情况下,一个JS文件会对应一个CSS文件
- serviceWorker.js是在开发React的时候启动的http服务器
分析React脚手架项目的启动
index.js文件
import React from 'react'; //导入React,一定要导,即使你没有用
import ReactDOM from 'react-dom'; //因为主要是操作DOM,所以这个是React操作DOM的
import './index.css'; //导入样式文件
import App from './App'; //导入App.js,它是一个组件
import * as serviceWorker from './serviceWorker'; //启用动开的时候后台服务,开启HMR热模块
//下面的代码就相当于 Vue当中的new Vue({})的代码。创建实例,接管区域,渲染组件
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister(); //当程序退出的时候,退出后台
React当中的语法使用的是JSX的语法,它不是完全的JS语法
认识JSX语法
它是一种全新的语法,也是比较流行一种语法,它将JS语法与HTML语法来进行混合使用,就是说可以在写JS的时候去插入HTML代码
React的开发完全用ES6及JSX 的语法,JSX本质上面所做的事情还是MVVM 的,只是换了一种方式在操作,它里面也有条件渲染,列表渲染,属性渲染,事件处理,组件化等操作(这些操作都是Vue当中自带的,只是在React里面要自己手写)
创建组件
在React当中一切皆组件,所以我们可以把CSS与好,JS也好都看成是一个组件,在目前创建组件的时候有两种方式,也就是目前React开发的两种方式
- 基于
class
的开发 - 基于
React Hooks Api
的开发(这是目前新堆出来的一种开发方式)
import React from "react"; //导入React
class App extends React.Component{
//在组件的内部,必须有一个方法render,这个方法负责在页面上面渲染数据
render(){
//render函数return的东西就是页面上面显示的东西
//在return的后面只能有一个根标题,与vue当中的template一样,也只能也有一个根标签
return (
<div>
<h1>这是一个1号标题</h1>
<h1>这是一个2号标题</h1>
</div>
);
}
}
export default App;
注意事项:组件的名称一定是大写开头的
扫描二维码关注公众号,回复: 12651569 查看本文章![]()
普通数据渲染
React最主要的一点就是与Vue是一样的,都是数据驱动页面,关注数据的变化就可以了,所以在React当中,它的数据应该在哪里呢?怎么渲染呢?
在Vue当中,我们的数据来源于三个地方,第一个是data
,第二个是computed
,第三个来源于父级props
。
在React当中,它的数据主要来源于两个地方,第一个是自身的数据state
,第二个是父级数据props
render(){
//render函数return的东西就是页面上面显示的东西
//在return的后面只能有一个根标题,与vue当中的template一样,也只能也有一个根标签
return (
<div>
<h1>这是一个1号标题------ {
this.state.userName} </h1>
<h1>这是一个2号标题</h1>
</div>
);
}
在JSX语法里面,如果在HTML标签当中要嵌入JS代码 则使用{}
包裹就可以了
条件渲染
//在组件的内部,必须有一个方法render,这个方法负责在页面上面渲染数据
render(){
//render函数return的东西就是页面上面显示的东西
//在return的后面只能有一个根标题,与vue当中的template一样,也只能也有一个根标签
return (
<div>
<h1>这是一个1号标题------ {
this.state.userName} </h1>
<h1>这是一个2号标题</h1>
<hr />
<p>{
this.state.age>=18?'成年':'未成年'}</p>
<hr />
{
this.state.age>=18&&<h2>这是一个非常好看的标签,age大于等于18就显示,否则就隐藏,怎么办?</h2>}
</div>
);
}
React当中的条件渲染使用的是之前ES基础里面的逻辑操作符的特性短路原则来实行的
列表渲染
React当中的列表渲染借助于是数组语法,在数组语法当中,我们有一个map
方法
<ul>
{
this.state.stus.map((item,index)=>{
return <li key={
index}>{
item}</li>
})}
</ul>
在做列表渲染的时候,与Vue一样,在每个渲染的元素上面要添加一个特殊的属性key
,保证它的唯一性
**注意事项:**在React当中会大量使用箭头函数,箭头函数后面是否跟花括号是完不一样的
上面的代码如果不跟花括号,可以写成如下。因为不跟花括号{}
则代表后面的东西是返回值
<ul>
{
this.state.stus.map((item,index)=>
<li key={
index}>{
item}</li>
)}
</ul>
**扩展:**如果我们现在需要在页面上面渲染10个button应该怎么办呢?
renderButton(){
let arr = [];
for(var i=0;i<10;i++){
arr.push(<button type="button">按钮{
i}</button>)
}
return arr;
}
render(){
return (
<div>
{
this.renderButton()}
</div>
);
}
在JSX代码当中可以直接把一部分代码重新封装成方法再进行。同时我们得出一些,列表渲染是需要得到一个数组再渲染
属性渲染
在Vue当中Vue如果要渲染属性需要使用v-bind:属性名
来进行绑定,但是在React当中完全没有必要,还是直接使用JSX
语法就行了
<button type="button" abc={
userName}> 按钮 </button><a href={
this.state.url1}>百度一下,你就知道</a>
始终记得一点,{}
里面的就是JS代码就可以了
样式设置
在React的JSX语法当中,有一点与众不同就是样式的设置,因为在JSX的内部class
是一个关键字,所以在设置元素的样式的时候,已经不能使用class
来设置,要转而使用另一个关键字className
App.css文件
.box1{
width: 100px;
height: 100px;
border: 2px solid red;
App.js文件
import "./App.css"; //导入CSS文件
<div className="box1">这是一个盒子</div>
重点:在之前的Vue里面,我们的<style scoped></style>
会有一个scoped
的属性,这个属性主要用于设置当前Vue文件内部的样式只作用于当前的<template>
,那么在React当中应该怎么实现这个功能呢?
上面的我们直接使用<div className="box1">这是一个盒子</div>
这是一个最普通的方式,它没有实现CSS的模块化
-
先将CSS文件名添加一个
.module
,如原来的App.css
就会变成App.module.css
文件 -
在App.js当中去导入的时候变成如下代码
import AppStyle from “./App.module.css”;
- 在使用的样式的时候应该如下使用
这是另一个盒子
动态样式绑定
constructor(){
super(...arguments);
this.state={
navType:1
}
}
render(){
return (
<div>
<ul className="navType">
<li className={
this.state.navType==0?'selected':null}>正在热映</li>
<li className={
this.state.navType==1?'selected':null}>即将上映</li>
</ul>
</div>
);
}
如果class的样式需要叠加的时候,在React当中会比较麻烦,但仍然有两种写法
1.
借用ES6当中的模板字符串去完在
<ul className="navType">
<li className={
`abc ${
this.state.navType===0?'selected':null}`}>正在热映</li>
<li className={
`abc ${
this.state.navType===1?'selected':null}`}>即将上映</li>
</ul>
2.
借用数组去完成
<ul className="navType">
<li className={
["abc",this.state.navType===0?'selected':null].join(' ')}>
正在热映
</li>
<li className={
["abc",this.state.navType===1?'selected':null].join(' ')}>
即将上映
</li>
</ul>
在React当中,React不建议我们去使用style
去设置属性,但是并不是不能,如果要用可以按下面的方式来使用
this.state={
styleObj:{
width:"100px",
height:"100px",
border:"1px solid black"
}
}
<div style={
this.state.styleObj}>
这是一个盒子
</div>
上面就是设置style
的过程,我们看起来操作很麻烦,需要先定义一个对象,然后style再去引用这个对象,但是我们平常在开发的时候,可能就直接写成下面的样式了
<div style={
{
width:"100px",height:"100px",border:"1px solid red"}}>
这又是一个盒子
</div>
组件化
之前已经学过了组件的创建,在本个环节,我们主要两个点
- 父级组件如何向子级组件传值
- 之前在
vue
当中的<slot>
在React是如何实现的
父级组件向子级组件传值
App.js
文件
<Home abc={
this.state.userName} userAge={
this.state.userAge}>
</Home>
Home.js
文件
<h2>{
this.props.abc}--------{
this.props.userAge}</h2>
React当中的自定义属性是支持驼峰命名的
Vue中Slot的实现方式
在以前的时候Vue可以通过Slot来向子组件的某个地方去插入数据,在React当中也有类似的实现的方式
App.js
文件中,我们在<Home>
组下面插入了一个东西
<Home abc={
this.state.userName} userAge={
this.state.userAge}>
<button type="button">这是通过Slot进来的</button>
</Home>
Home.js
的文件中,怎么接收插入的内容呢
<div>
{
this.props.children}
</div>
this.props.children
就是插槽的数据
事件及事件处理
在React的JSX
的语法当中,它的事件也是支持的,但是它的事件与做了相应的转换过程,如下所在
onclick
转变成了onClick
onchange
转变成了onChange
以前的事件名是全小写,现在on
后面根的事件类型名变成了大写
test(){
console.log(this);
alert("你好啊");
}
<button type="button" onClick={
this.test.bind(this)}>按钮2</button>
所以在上面的的样式绑定里面,我们可以通过事件去改变navType
以实现样式的改变
changeNavType(type){
console.log(type);
// 如果要改变state 的状态,要调用setState的方法
this.setState({
navType:type
});
}
<ul className="navType">
<li onClick={
this.changeNavType.bind(this,0)}
className={
["abc",this.state.navType===0?'selected':null].join(' ')}>
正在热映
</li>
<li onClick={
this.changeNavType.bind(this,1)}
className={
["abc",this.state.navType===1?'selected':null].join(' ')}>
即将上映
</li>
</ul>
React当中的单页面开发
在Vue当中Vue为了实现单页面开发使用的是vue-router
来跳转页面,而在React里面,它也有路由,它使用的是下面两个包
react-router
react-router-dom
这两个包的配置与vue-router
截然不同
安装路由的包
yarn add react-router react-router-dom --dev
配置路由
路由的配置方式有两种,第一种使用嵌套的方式在组件内部写,如下
App.js文件
import React from 'react';
import './App.css';
import {
HashRouter, Route, Switch } from "react-router-dom";
import Home from "./views/Home/Home";
import Detail from "./views/Detail/Detail";
class App extends React.Component {
//当一个路由嵌套另一个路由的时候,一定不能添加exact
render() {
return (
<HashRouter>
<Switch>
<Route path="/Home" component={
Home}></Route>
<Route path="/Detail" component={
Detail} exact></Route>
</Switch>
</HashRouter>
);
}
}
export default App;
Home.js文件
import React from "react";
import HomeStyle from "./Home.module.scss";
import ChooseFood from "../ChooseFood/ChooseFood";
import Order from "../Order/Order";
import {
Route } from "react-router-dom";
class Home extends React.Component{
render(){
return(
<div className={
HomeStyle.homePage}>
<div className={
HomeStyle.routerBox}>
<Route path="/Home/ChooseFood" component={
ChooseFood} exact></Route>
<Route path="/Home/Order" component={
Order} exact></Route>
</div>
<ul className={
HomeStyle.tabBar}>
</ul>
</div>
);
}
}
export default Home;
路由在渲染组件的时候,可以使用两种方式
<HashRouter>
<Switch>
<Route path="/Home" component={
Home}></Route>
<Route path="/Detail" exact render={
props => {
return <Detail></Detail>
}}></Route>
</Switch>
</HashRouter>
第一种是直接使用component
属性来渲染,第二种则是手动的调用render
函数,然后返回一个组件
我们的路由的第二种配置就是使用第二种render
函数来的
App.js的配置方法
import React from 'react';
import './App.css';
import {
HashRouter, Route, Switch,Redirect } from "react-router-dom";
import Home from "./views/Home/Home";
import ChooseFood from "./views/ChooseFood/ChooseFood";
import Category from "./views/Category/Category";
import Order from "./views/Order/Order";
import MySelf from "./views/MySelf/MySelf";
import Detail from "./views/Detail/Detail";
class App extends React.Component {
//当一个路由嵌套另一个路由的时候,一定不能添加exact
render() {
return (
<HashRouter>
<Switch>
<Redirect path="/" to="/Home/ChooseFood" exact></Redirect>
<Route path="/Home" render={
props => {
return <Home {
...props}>
<Route path="/Home/ChooseFood" component={
ChooseFood} exact></Route>
<Route path="/Home/Order" component={
Order} exact></Route>
<Route path="/Home/Category" component={
Category} exact></Route>
<Route path="/Home/MySelf" component={
MySelf} exact></Route>
</Home>
}}></Route>
<Route path="/Detail" component={
Detail} exact ></Route>
</Switch>
</HashRouter>
);
}
}
export default App;
Home.js页面
<div className={
HomeStyle.homePage}>
<div className={
HomeStyle.routerBox}>
{
this.props.children}
</div>
<div className={
HomeStyle.tabBar}>
<NavLink to="/Home/ChooseFood" activeClassName={
HomeStyle.active}>
<span className="iconfont iconcanju" style={
{
fontSize:"22px"}}></span>
点餐
</NavLink>
<NavLink to="/Home/Order" activeClassName={
HomeStyle.active}>
<span className="iconfont icondingdan" style={
{
fontSize:"22px"}}></span>
订单
</NavLink>
<NavLink to="/Home/Category" activeClassName={
HomeStyle.active}>
<span className="iconfont iconfenlei" style={
{
fontSize:"22px"}}></span>
分类
</NavLink>
<NavLink to="/Home/MySelf" activeClassName={
HomeStyle.active}>
<span className="iconfont iconyonghuming" style={
{
fontSize:"22px"}}></span>
我的
</NavLink>
</div>
</div>
如果需要通过JS的方法去跳转面页面,则可以找this.props.history
这个对象,它相当于Vue里面的this.$router