react库
用于构建用户界面的JavaScript库
注意!!! React是一个库不是一个框架
react库的特点:
- 声明式:
- 组件化:
- 一次学习,随处编写:版本的变动较小
react的生态现在是阿里做的
一、创建项目
通过script标签引入,在学习时一般直接引用cdn引入
-
通过react的脚手架,创建项目进行开发,部署
// 1.安装脚手架 cnpm installl -g create-react-app // 2.创建项目 create-react-app 01helloworld // 开发时运行的环境 cd 01helloworld npm start
二、React的渲染
使用jsx的写法,可创建js元素
注意:jsx的元素,必须要有一个根元素
let root = 这是根元素
使用函数的方式创建元素
let desc = "这是根组件";
function App(){
reture (
{desc}
)
}
export.default App
三、React组件传值
关于组件的创建
- 组件的创建第一种方法:函数式组件
function App () {
return (
这是一个组件
)
}
export default App
- 组件的创建第二种方法:变量式创建
const app = new App({
desc:'类组件是继承React.Component的'
}).render();
render(app,document.querySelector('#root'))
定义类的方式
import { render } from "react-dom";
class App extends React.Component{
render() {
// props是render函数传进来的参数的,是默认存在,不需要实际声明
return (
组件1
{this.props.desc}
)
}
}
render( ,document.querySelector('#root'));
注意!!!这是React16之后的写法,在这之前的js还没有扩展出类写法,因此在这之前一般采用以下的写法:
const App = React.createClass({
render(){
return xxxxxxx
}
});
render( ,document.querySelector('#root'));
四、JSX
JSX的优点:
- JSX执行更快,编译为JavaScript代码时进行优化
- 类型更安全,编译过程中能即时发现错误
- JSX编写模板更加简单快速(相对而言)
注意!!!
- Jsx与Vue类似,必须要有一个根节点
- 正常的普通HTML必须小写,大写会默认认为是组件
JSX内部的表达式:{}
- 可以使用大多数的JS表达式:如: 变量,函数,对象,条件运算符,三元运算符
- 可以直接使用HTML,不需要进行任何处理
- 在使用类名的时候尽量使用className,因为class是React的内置关键字
总结:
- JSX由HTML的元素构成
- 中间如果需要加入变量,需要用括号括起来
- 可以使用表达式,表达式中可以使用JSX对象
- 属性和对象内容都是用括号插入内容
五、JSX-Style样式
1.class中,不可以存在多个class属性
2.style样式中,如果存在多个单词时,第二个单词开始必须首字母大写,或者用-引起来,否则会报错
let exampleStyle = {
background:'skyblue',
borderBottom:'5px solid #ccc'
background-image:
"url('https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png')"
};
3. 多个类共存的操作
let ele4 = (
横着1
竖着2
);
let DOMElement = (
// 样式的类名要写className,因为class在React中是关键字
// 后面可以使用变量,也可以使用字符串
hello world
{1+1}
{str+time}
{str+localTime()}
{temp>37.2? :'不隔离'}
);
4. 关于JSX的注释
{/* 必须在表达式内书写注释,否则报错 */}
六、条件循环
1. 条件判断
2. 循环
1. 简单的循环方式
let arr = ['芜湖','起飞','南通','哈哈哈哈'];
// 循环渲染
class ParentCom extends React.Component{
constructor(props){
super(props)
}
render() {
let res = [];
arr.forEach((item,index)=>{
let temp = {item} ;
res.push(temp)
});
// 这里的循环方式也可以使用map的方法
return (
{res}
)
}
}
2. 简化后的循环方式
使用数据的map方法,对每一项数据按照jsx的形式进行加工,最终得到1个每一项都是jsx对象的数值,
七、组件
注意ReactDom.render()
一般只会放一个根组件,但是一个根组件可以加载无数的组件
1. 函数式组件
import {render} from "react-dom";
import React from 'react';
import logo from './logo.svg';
// props是父组件传进来的参数
// 比如 即: props.weather = '下雨'
function App(props) {
// 注意,在括号中可以任何有效的JavaScript表达式并用大括号引起来
return (
Edit src/App.js
and save to reload.
{desc}
{props.desc}
Learn React
);
}
2. 类组件
import {render} from "react-dom";
import React from 'react';
class App extends React.Component{
render() {
// props是render函数传进来的参数的,是默认存在,不需要实际声明
return (
组件1
{this.props.desc}
)
}
}
// 组件的是需要render函数返回模板
// 类组件不用刻意声明形参
// 比如 即: this.props.weather = '下雨'
3. 复合组件
class ChildCom extends React.Component{
render(){
return(
hello {this.props.name} !!!
)
}
}
class ParentCom extends React.Component{
render() {
// props是render函数传进来的参数的,是默认存在,不需要实际声明
return (
组件1
今天的天气是: {this.props.weather}
{this.props.desc}
)
}
}
// 复合组件传参的方式
//
4. 函数式与类组件的区别
- 类组件可以自定义事件,函数式组件不方便设置事件
- 内容定死,只传一些简单的参数,就是使用函数式组件,即为静态组件
- 函数式组件操作简单,但可支持功能较少
- 类组件用于交互和数据修改
注意!!!无论是类组件还是函数式组件的调用都是
这种的方式
八、props
1. 父传递子组件
要对子组件进行控制,如:是否显示,则只需要在父组件处传入一个布尔值即可:
// 父组件
class ParentCom extends React.Component{
constructor(props){
super(props);
this.state = {
isActive:true
};
this.changeShow = this.changeShow.bind(this)
}
changeShow(){
this.setState({
isActive:!this.state.isActive
})
}
render() {
return (
这是父元素控制子元素的操作
)
}
}
// 子组件
class ChildCom extends React.Component{
constructor(props){
super(props)
}
render() {
let ele = null;
if (this.props.isActive) {
return (
这是子组件
)
// 需要注意这里无论如何都需要返回一个模板对象
}else {
return (
null
)
}
}
}
2. 子组件向父组件数据传递
// 实现子传父
class ParentCom extends React.Component{
constructor(props) {
super(props);
this.state = {
childData:'',
}
}
setChildData=(data)=>{
this.setState({
childData:data
})
};
render() {
return (
这个是子元素传递给父元素的数据:{this.state.childData}
{/* 往子组件处传递一个函数,用以控制父组件的内容 */}
)
}
}
class ChildCom extends React.Component{
constructor(props){
super(props);
this.state = {
msg:'hello world'
};
// 这里的绑定也可以进行绑定
this.sendData = this.sendData.bind(this)
}
sendData(){
console.log(this.state.msg);
this.props.setChildData(this.state.msg)
}
render() {
return (
)
}
}
九、React事件
特点:
- react事件,绑定事件的命名,驼峰命名
- 传入1个函数,而不是字符串,如果的
事件对象:
React返回的事件对象是代理处理后的事件对象,如果想要查看事件对象的具体值,必须之间输出事件对象的属性
原生的JS,可以直接使用return false,来阻止浏览器的默认行为
但是因为React代理处理了原生JS使得return false 变为无效,要阻止浏览器的默认行为就使用 e.preventDefault
React事件传参
-
使用函数的方式
-
不使用箭头函数方式
十、组件条件循环渲染
1. 三元运算符
// 组件1
function UserGreet() {
return (
你好,尊敬的用户
)
}
// 组件2
function UserLogin() {
return (
你好请登录
)
}
// 条件渲染的主组件
class ParentCom extends React.Component{
constructor(props){
super(props);
this.state = {
isLogin:false,
}
}
changeEvent = (e)=>{
console.log(e);
this.setState({isLogin:!this.state.isLogin})
};
render() {
let ele = null;
/*
条件渲染组件的方式
if (this.state.isLogin){
ele =
}else {
ele =
}*/
// 这里可以使用三元运算符
ele = this.state.isLogin? : ;
return (
这是头部
{ele}
这是尾部
)
}
}
2. 列表循环渲染
十一、React制作疫情地图
1.疫情数据的API接口
注意!!! (不允许跨域请求)
https://c.m.163.com/ug/api/wuhan/app/index/feiyan-data-list?t=1580892891419
2.写入一个Json数据文件
3.导入Json数据
import jsonData from "./feiyan";
console.log(jsonData);
4.设置(设计)数据模型
let provinceObj = {
// "广东省":{
// confirm:'',
// suspect:'',
// heal:'',
// deal:''
// }
};
5.进行数据累加
jsonData.data.list.forEach((item,index)=>{
// 数据的初始化处理
if (provinceObj[item.province]===undefined){
provinceObj[item.province] = {
confirm:0,
suspect:0,
heal:0,
dead:0,
}
}
// 数据异常处理
item.confirm = item.confirm?item.confirm:0;
item.suspect = item.suspect?item.suspect:0;
item.heal = item.heal?item.heal:0;
item.dead = item.dead?item.dead:0;
// 对数据进行累加处理,以获取每个省份的数值
provinceObj[item.province] = {
confirm:provinceObj[item.province].confirm+item.confirm,
suspect:provinceObj[item.province].suspect+item.suspect,
heal:provinceObj[item.province].heal+item.heal,
dead:provinceObj[item.province].dead+item.dead,
}
});
let provinceList = [];
for (let item in provinceObj) {
provinceObj[item].province = item;
provinceList.push(provinceObj[item])
}
6.对数据进行排序
// 对数组进行降序排序
let provinceListSort = provinceList.sort((a,b)=>{
if (a.confirm > b.confirm) {
return -1
}else {
return 1
}
});
7.将数据渲染至页面上
import React from 'react';
import ReactDOM from 'react-dom';
class ParentCom extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
中国病例
-
地区
确诊
死亡
疑似
{
this.props.list.map((item,index)=>{
return (
-
{item.province}
{item.confirm}
{item.dead}
{item.suspect}
)
})
}
);
}
}
ReactDOM.render(,document.querySelector('#root'));
十二、React的生命周期
生命周期的3个状态:
- mount:挂载
- update:数据更新
- unMount:卸载
十三、 表单
- 必须绑定value值
- 必须绑定onChange事件
十四、Ajax与React
本次小案例运用到的是技术有:
- axios网路请求
- express后端框架
- React前端框架
- AJax异步请求
1.API接口
https://i.snssdk.com/ugc/hotboard_fe/hot_list/template/hot_list/forum_tab.html?activeWidget=1
获取到首页的信息后查看Ajax的数据请求
可以获取到首页的数据请求
以及
2.建议服务器
- express --view=ejs react-serve
- cd react-serve
- npm install
3.axios的安装
- npm install axios
十五、React实现todoList
复习一下React的事件机制
涉及到的技术有:Ref以及键盘事件
十六、关于prop-types
1.prop-types介绍
prop-types是用于限制父组件传给子组件的数据类型,以及是否为必须的数据
prop-types的报错只是表明与声明的规范不一致导致的报错,并不一定会影响最终的DOM渲染
2. prop-types的安装
自从React V15之后,prop-type就作为单独的插件,需要另外的安装,而且也不是必须使用的插件
安装:
npm i prop-types --save
3.prop-types的使用
// 1. 导入prop-types
// ES6的写法
import PropTypes from 'prop-types';
// ES5的写法
var PropTypes = require('prop-types');
// 2. 创建一个组件
class MyComponent extends React.Component {
construction(props){
super(props)
}
render() {
// ... 写入需要生成的DOM元素
}
}
// 3. 使用prop-types
MyComponent.propTypes = {
// 定义类型为字符串
desc:PropTypes.string,
// 定义类型为数字类型
x:PropTypes.number,
// 定义类型为数字类型,且为必须的数字类型
y:PropTypes.number.isRequrie
}
// 4. 使用prop-types的默认属性值
MyComponent.defaultProps = {
y:2
};
当然还有另外一种写法:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
title:this.props.title
};
console.log(this.props);
}
static propTypes = {
desc:PropTypes.string,
x:PropTypes.number,
y:PropTypes.number.isRequired
};
static defaultProps = {
y:2
};
render() {
return (
这是{this.state.title}
{this.props.children}
{this.props.x+this.props.y}
);
}
}
十七、React插槽
组件中写入自定义内容,这些内容可以被识别和控制,
1.原理
插槽的内容会默认传入props.children处,直接调用可以使用this.props.children
组件中的HTML内容直接全部插入,调用{this.props.children}
根据HTML内容的不同插入的内容也不同的,(即对组件插槽进行处理)
// 父组件
这是放置头部的内容
这是放置主要内容的内容
这是放置尾部的内容
// 定义子组件
class ChildCom extends React.Component {
render() {
let headerCom,mainCom,footerCom;
this.props.children.forEach((item, index)=>{
if (item.props["data-position"] === "header"){
headerCom = item
} else if (item.props["data-position"] === "main") {
mainCom = item
}else {
footerCom = item
}
});
return (
{headerCom}
{mainCom}
{footerCom}
);
}
}
十八、 React 路由
1.安装
cnpm i react-router-dom --save
2.路由的三大组件
- Router:所有的路由的根组件
- Link:用于页面的跳转相当于HTML的A标签
- Route:路由根组件下面匹配的组件
3.写一个简单的路由
Home
Product
Me
{/* 如果需要精确匹配就需要加入exact属性 */}
4.路由传参
外面显示的所有内容:
Home
Product
Me
{/* 如果需要精确匹配就需要加入exact属性 */}
5.路径切换
路由的切换,默认采用的push方法,可以前进后退
replace:进入的该路由之后,就会将该路由设置为默认首页,此时不可以前进或者后退
Me
6.动态路由
News
{/* this.props.match.params.id 获取动态路由的信息 */}
7.路由重定向
// 当访问到LoginInfo组件的是否,该组件会跟条件重定向至不同的内容
function LoginInfo(props) {
// props.loginState = "success";
// props.loginState = "fail";
console.log(props);
if (props.location.state.loginState === "success"){
return (
)
}else {
return (
)
}
}
8.路由函数式导航
class ChildCom extends React.Component {
toIndex = ()=>{
console.log(this.props);
this.props.history.push("/",{msg:'从childCom发给首页的数据'})
{/* 首页接收数据是以 this.props.location.state.msg */}
};
render() {
return (
);
}
}
9.Switch组件
让switch组件内容的route只匹配1次,只要匹配到了内容,便不会往下匹配
{/* 此时不会显示abc2页面 */}
(这是abc1页面
)} />
(这是abc2页面
)} />
十九、Redux状态管理树
解决React数据管理(状态管理),用于中大型项目,数据比较庞大,且组件间的数据交互多的情况下使用
Redux的特点:
- Store:数据仓库,保存数据的地方
- state:state是一个对象,数据仓库的所有数据都放到state里面
- action:与Vue有点区别,action就是一个动作用于触发数据改变的方法,不是用于Ajax异步请求
- dispatch:将action动作触发成方法
- Reducer:是一个函数,通过获取动作,改变数据生成一个新的状态state从而改变页面
1.安装Redux
cnpm install redux --save
2.初始化仓库
// 1.导入redux
// 2.创建store仓库
const store = createStore(reducer);
// 3.初始化仓库数据以及方法
const reducer = function (state = {num: 0}, action) {
console.log(action); // 输出{type: "add"}
switch (action.type) {
case "add":
state.num++;
break;
case "decrement":
state.num--;
break;
}
return {...state}
};
// 4.调用数据
function add() {
// 通过仓库的方法进行修改数据
store.dispatch({type: "add"});
// console.log(store.getState());
}
function decrement() {
// 通过仓库的方法进行修改数据
store.dispatch({type:"decrement"})
}
// 获取数据的方式
let state = store.getState()
// 5.修改视图--监听数据的变化重新渲染视图
store.subscribe(()=>{
ReactDOM.render( , document.getElementById('root'));
}
)
3.React-redux
安装:
cnpm i react-redux --save
概念:
- Province
使用:
-
初始化仓库数据
function reducer(state=0,action) { switch (action.type) { case "add": state.num++; break; case "decrement": state.num--; break; default: break; } return {...state} }
-
实例化数据仓库
const store = createStore(reducer);
-
数据的获取--映射函数
// 设置action let addAction = { type:"add" } // 将state映射到props函数中 function mapStateToProps(state) { return { value:state.num, } } // 将修改state数据的方法,映射到props,默认会传入store里的dispatch方法 function mapDispatchToProps(dispatch) { return { onAddClick:()=>{ dispatch(addAction) }, onDecrementClick:()=> dispatch({type:"decrement"}) } }
-
将两个映射函数结合成一个新的App函数
const App = connect( mapStateToProps, mapDispatchToProps )(Counter)
-
渲染组件
ReactDOM.render(