一、函数组件
1、函数组件的创建
函数组件:使用JS的函数(或箭头函数)创建的组件称为函数组件,函数组件有如下约定
- 函数名称必须以大写字母开头
- 函数组件必须有返回值,返回JSX表达式
- 渲染函数组件:用函数名作为组件标签名
- 组件名称可以是单标签也可以是双标签
export default function Hello(){
return (
<div>
Hello Function Component
</div>
)
}
VSCode 中快捷键
rfc
可自动生成。
创建完函数组件,可以将其引入到App.jsx中
import './App.css'
import Hello from './Hello';
function App() {
return (
<div>
<Hello></Hello>
</div>
);
}
export default App;
2、函数组件事件处理
注意:函数组件中绑定方法不需要this
export default function Hello() {
const clickEvent = () => {
console.log('2');
}
const getParams = (params) => {
console.log(params);
}
return (
<>
<button onClick={() => {
console.log('1');
}}>按钮</button>
<button onClick={clickEvent}>按钮</button>
<button onClick={() => getParams('3')}>传参</button>
</>
)
}
3、函数组件的Prop
3.1、函数组件的Props
import React from 'react';
import ReactDOM from 'react-dom';
function LoginForm(props){
return <h1>{props.title}登录</h1>;
}
const template=<LoginForm title='管理员'></LoginForm>
ReactDOM.render(template,document.getElementById('root'));
当然也可以自己在调用函数组件的时候指定其他的,比如下面这个例子输入会员,就会变成会员登录
import React from 'react';
import ReactDOM from 'react-dom';
function LoginForm(props){
return <h1>{props.title}登录</h1>;
}
const template=<LoginForm title='会员'></LoginForm>
ReactDOM.render(template,document.getElementById('root'));
下面我们再定义一个函数式组件,然后在这里边传递多个参数
import React from 'react';
import ReactDOM from 'react-dom';
function UserInfo(props){
console.log(props);
const template=(
<div>
<ul>
<li>姓名:{props.username}</li>
<li>年龄:{props.age}</li>
<li>特长:{props.specialty}</li>
</ul>
</div>
);
return template;
}
const template=(
<div>
<UserInfo username={'马保国'} age={56} specialty={'太极'}></UserInfo>
</div>
);
ReactDOM.render(template,document.getElementById('root'));
显示效果如下所示,我们通过对控制台的观察,会发现props就是传递的JS对象的值
如上给组件赋值除了赋常量外也可以传递变量,如下所示
import React from 'react';
import ReactDOM from 'react-dom';
function UserInfo(props){
const template=(
<div>
<ul>
<li>姓名:{props.username}</li>
<li>年龄:{props.age}</li>
<li>特长:{props.specialty}</li>
</ul>
</div>
);
return template;
}
const u={
username:'马保国',
age:69,
specialty:'打太极'
};
const template=(
<div>
<UserInfo username={u.username} age={u.age} specialty={u.specialty}></UserInfo>
</div>
);
ReactDOM.render(template,document.getElementById('root'));
其实还有简写方式
import React from 'react';
import ReactDOM from 'react-dom';
function UserInfo(props){
const template=(
<div>
<ul>
<li>姓名:{props.username}</li>
<li>年龄:{props.age}</li>
<li>特长:{props.specialty}</li>
</ul>
</div>
);
return template;
}
const u={
username:'马保国',
age:69,
specialty:'打太极'
};
const template=(
<div>
<UserInfo {...u}></UserInfo>
</div>
);
ReactDOM.render(template,document.getElementById('root'));
3.2、props默认值
首先,先来完成一个函数组件的默认值案例
import React from 'react';
import ReactDOM from 'react-dom';
function UserInfo(props){
const template=(
<div>
<ul>
<li>姓名:{props.username}</li>
<li>年龄:{props.age}</li>
<li>特长:{props.specialty}</li>
</ul>
</div>
);
return template;
}
//设置默认值的语法 组件名.defaultProps
UserInfo.defaultProps={
username:'无名氏',
age:0,
specialty:'无特长'
}
const template=(
<div>
<UserInfo username='张明理'></UserInfo>
</div>
);
ReactDOM.render(template,document.getElementById('root'));
这里如果在调用组件的时候赋值,那么默认值就不会生效了,倘若,默认值就会生效。
3.3、props验证器
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
function UserInfo(props){
const template=(
<div>
<ul>
<li>姓名:{props.username}</li>
<li>年龄:{props.age}</li>
<li>特长:{props.specialty}</li>
</ul>
</div>
);
return template;
}
UserInfo.propTypes={
username:PropTypes.string.isRequired,
age:PropTypes.number.isRequired,
specialty:PropTypes.string
}
const template=(
<div>
<UserInfo age={'20岁'} specialty='打羽毛球'></UserInfo>
</div>
);
ReactDOM.render(template,document.getElementById('root'));
4、有状态组件和无状态组件
- 函数组件又叫做无状态组件,类组件又叫做有状态组件
- 状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
- 函数组件没有自己的状态,只负责数据展示
- 类组件有自己的状态,负责更新UI
二、Hook简介
1、hook的由来和作用
react16.8以后的新特性Hooks函数组件在react16.8以前函数组件只能被动接收外部数据,并且没有自己的生命周期钩子函数,函数内部也没有this可用新特性Hookhook推出的动机主要是因为类组件有一下几个不足
- 组件之间复用公共逻辑比较麻烦,以前常见的提取组件公共逻辑的方式有高阶组件/renderProps等,但这些方式或多或少都对原有组件的代码组织方式有一定的破坏性
- 复杂组件变得难以理解(例如相同的逻辑可能要写在不同的生命周期钩子函数里面)
- 难以理解的class(比如对新手来见,class组件中的this不太好理解)
新特性hook出现之后,函数组件就可以完全替代类组件,但是这并不是说react官方会抛弃类组件,react官方文档中也表明了没有计划会在react中移除class组件。
注意:hook特性只能在函数组件中使用
三、State Hook
1、作用
useState 为函数组件提供了状态(state)
2、基本使用
2.1、使用步骤
- 导入
useState
函数
import { useState } from 'react'
- 调用
useState
函数,并传入状态的初始值,从useState
函数的返回值中,拿到状态和修改状态的方法
const [变量名, 方法名] = useState(数据初始值);
- 在jsx中展示状态
- 使用修改状态的方法更新状态
2.2、代码实现
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0);
const decrement = () => {
setCount(count - 1)
}
return (
<>
<h1>计数器:{count}</h1>
<button onClick={decrement}>-1</button>
<button onClick={() => {setCount(count + 1)}}>+1</button>
</>
)
}
注意:修改数据的 set 方法,只需要接收一个新数据作为参数,方法内部会自动用接收到的新数据来覆盖旧数据。
3、函数作为参数
- 语法
const [变量名, 方法名]=useState(()=>{return '计算之后的初始值'})
- 语法规则 - 回调函数return出去的值作为
变量名
的初始值- 回调函数中的逻辑只会在组件初始化的时候执行一次 - 语法选择 - 如果初始化一个普通的数据,直接使用
useState(初始值)
即可- 如果要初始化的数据无法直接得到需要通过计算才能获取到,使用useState(()=>{})
- 案例实现
import {useState} from 'react'
function Counter(props){
const [count,setCount]=useState(()=>{
return props.count
})
return(
<>
<h2>{count}</h2>
<button onClick={()=>setCount(count+1)}>+</button>
</>
)
}
function App() {
return(
<>
<Counter count={10}></Counter>
<Counter count={20}></Counter>
</>
)
}
export default App;
四、 Effect Hook
1、作用
- 副作用:副作用是相对与主作用而言的,一个函数除了主作用,其他作用都是副作用,对于React组件来说,主作用是根据数据(state/props)渲染UI,除此之外都是副作用
- 常见的副作用 - 数据请求Ajax发送- 手动修改DOM- localStorage操作
- Effect Hook 可以让你在函数组件中执行副作用操作
import {useState,useEffect} from 'react'
export default function Example() {
const [count,setCount]=useState(0)
useEffect(()=>{
document.title=`You clicked ${count} times`
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>Click Me</button>
</div>
)
}
2、useEffect 的参数
import { useEffect } from 'react'
useEffect(() => {}, []);
useEffect 的参数,主要分为两个,第一个固定是一个回调函数,第二个是一个数组(可选)。
参数传递的不同,useEffect 实现的效果也不同。
2.1、没有第2个参数
当 useEffect 只有第一个参数时,其作用就是在模拟
componentDidMount
和
componentDidUpdate
生命周期函数。
也就是说,useEffect 的第一个回调函数,会在组件首次挂载完成执行一次,同时,后续组件每次更新完成时也会执行。
useEffect(() => {
// ...
})
关键代码如下所示
import {useState,useEffect} from 'react'
export default function Params() {
const [count,setCount]=useState(0)
useEffect(()=>{
console.log('没有第2个参数');
})
return (
<div>
<h1>{count}</h1>
<button onClick={()=>setCount(count+1)}>+1</button>
</div>
)
}
执行的效果是:组件首次挂载完成执行一次,每次单击按钮会执行一次
2.2、第2个参数是空数组
当 useEffect 的第二个参数是一个空数组是,其作用就是在模拟
componentDidMount
生命周期函数。
也就是说,useEffect 的第一个回调函数,会在组件首次挂载完成执行一次。
useEffect(() => {
// ...
}, [])
关键代码如下所示
import {useState,useEffect} from 'react'
export default function Params() {
const [count,setCount]=useState(0)
useEffect(()=>{
console.log('没有第2个参数');
},[])
return (
<div>
<h1>{count}</h1>
<button onClick={()=>setCount(count+1)}>+1</button>
</div>
)
}
执行的效果是:只有在组件首次挂载完成执行一次,后续单击不会执行
2.3、第2个参数是非空数组
当 useEffect 的第二个参数是一个非空数组时,其作用就是在模拟
componentDidMount
生命周期函数,同时还可以模拟 Vue 中 watch 的作用。
也就是说,useEffect 的第一个回调函数,会在组件首次挂载完成执行一次。后续,只要当第二个参数的数组中,任意一条数据发生改变,useEffect 的第一个回调函数又会再次执行。
useEffect(() => {
// ...
}, [数据1, 数据2, ...])
关键代码如下所示
import {useState,useEffect} from 'react'
export default function Params() {
const [count,setCount]=useState(0)
const [name,setName]=useState('张三')
useEffect(()=>{
console.log('第2个参数是非空数字');
},[count])
return (
<div>
<h1>{count}</h1>
<h1>{name}</h1>
<button onClick={()=>setCount(count+1)}>+1</button>
<button onClick={()=>setName('李四')}>更新</button>
</div>
)
}
执行的结果是:在组件首次挂载完成执行一次,后续只有在点击+1操作按钮的时候才会调用useEffect的回调函数。单击更新按钮不会触发useEffect回调函数的执行
3、清理副作用
当 useEffect 的第一个参数中,返回了一个函数。那么,返回的这个函数就是在模拟
componentWillUnmount
生命周期函数。
在组件被销毁时,如果有些副作用操作需要被清理,在这里可以写清理副作用的代码。
useEffect(() => {
return () => {
}
})
关键代码
import { useEffect } from 'react'
export default function ClearEffect() {
useEffect(() => {
let times=setInterval(() => {
console.log('定时执行操作');
}, 1000);
return ()=>{
clearInterval(times)
}
}, [])
return (
<div>this is test</div>
)
}
***************************************************************************************
import ClearEffect from "./ClearEffect"
import { useState } from "react"
export default function App() {
const [flag,setFlag]=useState(true)
return (
<div>
{flag? <ClearEffect/>:null}
<button onClick={()=>setFlag(!flag)}>switch</button>
</div>
)
}
4、useEffect-网络请求
import axios from 'axios'
import React, { useState, useEffect } from 'react'
export default function User() {
const [users, setUsers] = useState([])
const getUsersApi = async () => {
let result = await axios.get('http://39.106.34.185:8888/user')
setUsers(result.data.data.list)
}
useEffect(() => {
getUsersApi()
}, [])
return (
<div>
<table>
<tr>
<td>昵称</td>
<td>手机号</td>
<td>绑定汽车数量</td>
<td>订单数量</td>
<td>未缴费订单数量</td>
<td>状态</td>
<td>创建事件</td>
<td>操作</td>
</tr>
{
users.map(item => <tr key={item.id}>
<td>{item.name}</td>
<td>{item.tel}</td>
<td>{item.carNum}</td>
<td>{item.orderNum}</td>
<td>{item.orderNum}</td>
<td>{item.state==1?'启用':'禁用'}</td>
<td>{item.createTime}</td>
<td>
<span>查看</span>
<span>订单详情</span>
<span>更多</span>
</td>
</tr>)
}
</table>
</div>
)
}
五、 useRef
1、作用
在函数组件中获取DOM元素或者组件对象
2、使用步骤
- 导入
useRef
函数
import { useRef } from 'react'
- 执行
useRef
函数,返回一个ref对象
function 组件名() {
const 变量名 = useRef();
}
- 绑定 ref
找到函数组件中对应的节点,通过
ref
属性将 ref 对象绑定到元素节点身上:
function 组件名() {
const 变量名 = useRef();
return (
<节点 ref={变量名}></节点>
)
}
- 获取元素节点
当元素通过
ref
绑定了元素后,就可以通过 ref 对象来获取元素节点了:
function 组件名() {
const 变量名 = useRef();
return (
<节点 ref={变量名} onClick={() => {
console.log(变量名.current); // 元素节点
}}></节点>
)
}
3、代码实现
import React,{useRef} from 'react'
import './Ball.css'
export default function Ball() {
const ballRf=useRef()
const changeBall=()=>{
ballRf.current.style.backgroundColor="springgreen"
}
return (
<div>
<div className="box" ref={ballRf}></div>
<button onClick={changeBall}>变化</button>
</div>
)
}
六、useMemo
1、作用
useMemo的作用类似vue中的计算属性computed,即根据母体数据衍生出新的数据,一旦母体数据发生变化,则useMemo会自动执行
2、基础语法
import { useMemo } from 'react'
const 变量名 = useMemo(() => {
return 计算得到的数据;
}, [依赖的原数据])
最终,计算得到的数据,就会通过 return 保存到变量身上。
关键代码如下所示
import {useState,useMemo} from 'react'
export default function App() {
const [fnum,setFnum]=useState(10)
const [snum,setSnum]=useState(20)
const sum=useMemo(()=>{
return fnum+snum
},[fnum,snum])
return (
<div>
<h1>{sum}</h1>
<button onClick={()=>setFnum(fnum+2)}>fnum+2</button>
<button onClick={()=>setSnum(snum+3)}>snum+3</button>
</div>
)
}
3、使用hook实现购物车功能
import axios from 'axios'
import React, { useState, useEffect,useMemo } from 'react'
import './ShopCartList.css'
export default function ShopCartList() {
const [list, setList] = useState([])
const fetchShopCartData = async () => {
const result = await
axios.get('http://www.zhaijizhe.cn:3001/shopcart/getShopcartData')
console.log(result.data);
setList(result.data.data)
}
const total=useMemo(()=>{
return list.filter(item=>item.checked).reduce((pre,cur)=>pre+cur.price*cur.num,0)
},[list])
const changeNum=async(_id,n)=>{
let result=await
axios.post('http://www.zhaijizhe.cn:3001/shopcart/changeNum',{_id,n})
if(result.data.code){
fetchShopCartData()
}
}
const checkItem=async(_id)=>{
let result=await
axios.get('http://www.zhaijizhe.cn:3001/shopcart/checkProducts',{params:{_id}})
if(result.data.code){
fetchShopCartData()
}
}
const changeNum1=(_id,index,n)=>{
list[index].num=n
setList(()=>{
return[
...list
]
})
}
const submitChangeNum=async(_id,n)=>{
let result=await
axios.post('http://www.zhaijizhe.cn:3001/shopcart/changeNumByInput',{_id,n})
if(result.data.code){
fetchShopCartData()
}
}
useEffect(() => {
fetchShopCartData()
}, [])
return (
<div>
<h1>购物车</h1>
<table>
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
</tr>
</thead>
<tbody>
{
list.map((item,index)=><tr key={item._id}>
<td>
<input type='checkbox'
onChange={()=>checkItem(item._id)}
checked={item.checked}/>
</td>
<td>{item.name}</td>
<td>{item.price}</td>
<td>
<button onClick={()=>changeNum(item._id,-1)}>-</button>
<input type="text" value= {item.num}
onChange={(e)=>
{changeNum1(item._id,index,e.target.value)}}
onBlur={(e)=>
{submitChangeNum(item._id,e.target.value)}}/>
<button onClick={()=>changeNum(item._id,1)}>+</button>
</td>
<td>{item.price*item.num}</td>
</tr>)
}
<tr>
<td colSpan={5} style={{textAlign:'right'}}>
总计:{total}
</td>
</tr>
</tbody>
</table>
</div>
)
}
七、echarts
1、React引入echarts
- 安装echarts
yarn add echarts
- 自定义组件
import React,{useEffect} from 'react'
import * as echarts from 'echarts';
export default function ChartBar(props) {
const {optionsData = null, id = 'default-id', width = 600, height = 200,title="echart演示",seriesName} = props;
useEffect(()=>{
let xData=optionsData.xdata
let yData=optionsData.ydata
const options={
title: {
text:title
},
tooltip: {},
xAxis: {
data: xData
},
yAxis: {},
series: [
{
name: seriesName,
type: 'bar',
data: yData
}
]
}
const chart = echarts.init(document.getElementById(id));
chart.setOption(options);
},['optionsData'])
return (
<div id={id} style={{width: width, height: height}}>222</div>
)
}
- 引入
import React,{useState} from 'react'
import ChartBar from './views/ChartBar'
export default function App() {
const [echarts,setEcharts]=useState({
xdata:['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
ydata: [5, 20, 36, 10, 10, 20]})
return (
<div>
<ChartBar
id="chart-bar"
optionsData={echarts}
title={"echart演示"}
seriesName={"销量"}
width={880}
height={300}></ChartBar>
</div>
)
}
2、柱状图的配置
2.1、常见效果设置
- 最大值、最小值、平均值标记设置
series: [
{
name: seriesName,
type: 'bar',
data: yData,
markPoint:{
data:[
{
type:'max',name:'最大值'
},
{
type:'min',name:'最小值'
}
]
},
markLine:{
data:[
{
type:'average',name:'平均值'
}
]
}
}
]
- 图形上的文本标签的设置
series: [
{
label:{
show:true,
rotate:65,
color:'#f00',
backgroundColor:'#ff0',
position:'top'
}
}
]
- 图形的样式设置
series: [
{
itemStyle:{
color:'#f00'
}
}
]
- 更改柱条的宽度
series: [
{
barWidth:15
}
]
- 更改x轴和y轴的角色
const options={
xAxis: {},
yAxis: { data: xData},
}
2.2、title的相关配置
属性类型含义textstring主标题文本linkstring主标题超链接textStyleobjectcolor:主标题文字的颜色。
fontStyle:主标题的风格
fontWeight:主标题字体的粗细backgroundColorColor背景色borderColorColor边框颜色borderRadiusnumber|Array圆角半径
const options={
title: {
text:title,
link:'http://www.zhaijizhe.cn',
textStyle:{
color:'#00ffff',
fontStyle:'lighter',
fontSize:38
},
backgroundColor:'#ff0',
borderColor:'#000',
borderRadius:15
}
}
2.3、tooltip的相关配置
tooltip:提示框组件,用于配置鼠标滑过或点击图标时的显示框
- 触发类型:trigger
- 触发时机:triggerOn
- 格式化:formatter
const options={
tooltip:{
show:true,
trigger:'axis',
triggerOn:'click',
formatter:`{b}的销量是{c}`
}
}
2.4、toolbox的相关配置
toolbox:ECharts提供的工具栏:内置有导出图片,数据视图,动态类型切换,数据区域缩放,重置五个工具
const options={
toolbox:{
feature:{
saveAsImage:{},
restore:{},
dataView:{
show:true
},
dataZoom:{},
magicType:{
type:['bar','line']
}
}
}
}
2.5、legend的相关配置
legend:图例,用于筛选系列,需要和series配置使用
- legend中的data是一个数组
- legend中的data的值需要和series数组中某组数据的name值一致。
import React,{useEffect} from 'react'
import * as echarts from 'echarts';
export default function ChartBar(props) {
const {optionsData = null, id = 'default-id', width = 600, height = 200,title="echart演示"} = props;
useEffect(()=>{
let xData=optionsData.xdata
let y1Data=optionsData.y1data
let y2Data=optionsData.y2data
let y3Data=optionsData.y3data
const options={
title: {
text:title
},
tooltip: {},
xAxis: {
data: xData
},
yAxis: {},
legend: {
data: ['1月份销量', '2月份销量', '3月份销量']
},
series: [
{
name: "1月份销量",
type: 'bar',
data: y1Data
},
{
name: "2月份销量",
type: 'bar',
data: y2Data
},
{
name: "3月份销量",
type: 'bar',
data: y3Data
}
]
}
const chart = echarts.init(document.getElementById(id));
chart.setOption(options);
},['optionsData'])
return (
<div id={id} style={{width: width, height: height}}>222</div>
)
}
import React,{useState} from 'react'
import ChartBar from './views/ChartBar1'
export default function App() {
const [echarts,setEcharts]=useState({
xdata:['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
y1data: [5, 20, 36, 10, 10, 20],
y2data: [3, 10, 26, 5, 12, 22],
y3data: [2, 12, 6, 15, 22, 52]
}
)
return (
<div>
<ChartBar
id="chart-bar"
optionsData={echarts}
title={"echart演示"}
width={880}
height={300}></ChartBar>
</div>
)
}
3、折线图的配置
2.1、基本配置
import React,{useEffect} from 'react'
import * as echarts from 'echarts';
export default function ChartBar(props) {
const {optionsData = null, id = 'default-id', width = 600, height = 200,title="echart演示",seriesName} = props;
useEffect(()=>{
let xData=optionsData.xdata
let yData=optionsData.ydata
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
name: seriesName,
type: 'line',
data: yData,
}
]
}
const chart = echarts.init(document.getElementById(id));
chart.setOption(options);
},['optionsData'])
return (
<div id={id} style={{width: width, height: height}}>222</div>
)
}
import React,{useState} from 'react'
import ChartBar from './views/ChartBar'
export default function App() {
const [echarts,setEcharts]=useState({
xdata:['1月', '2月', '3月', '4月', '5月', '6月','7月','8月','9月','10月','11月','12月'],
ydata: [5, 20, 36, 10, 10, 20,89,100,22,56,78,99]})
return (
<div>
<ChartBar
id="chart-bar"
optionsData={echarts}
title={"某培训机构2021年全年招生"}
seriesName={"招生量"}
width={880}
height={600}></ChartBar>
</div>
)
}
2.2、常见效果设置
- 最大、最小、平均值标记、设置标注区域
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
name: seriesName,
type: 'line',
data: yData,
markPoint:{
data:[
{
type:'max'
},
{
type:'min'
}
]
},
markLine:{
data:[
{
type:'average'
}
]
}
}
]
}
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
name: seriesName,
type: 'line',
data: yData,
markPoint:{
data:[
{
type:'max'
},
{
type:'min'
}
]
},
markLine:{
data:[
{
type:'average'
}
]
},
markArea:{
data:[
[
{
xAxis:'1月'
},
{
xAxis:'2月'
}
],
[
{
xAxis:'8月'
},
{
xAxis:'9月'
}
]
]
}
}
]
}
- 线条控制:平滑、风格
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
smooth:true,
lineStyle:{
color:'green',
type:'dotted'
}
]
}
- 填充风格
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
areaStyle:{
color:'skyblue'
}
]
}
2.3 多线设置
import React,{useEffect} from 'react'
import * as echarts from 'echarts';
export default function ChartBar(props) {
const {optionsData = null, id = 'default-id', width = 600, height = 200,title="echart演示",seriesName} = props;
useEffect(()=>{
let xData=optionsData.xdata
let yData=optionsData.ydata
let y2Data=optionsData.y2data
const options={
title:{
text:title
},
xAxis: {
data: xData
},
yAxis: { },
series: [
{
name: seriesName,
type: 'line',
data: yData,
},
{
name: seriesName,
type: 'line',
data: y2Data,
}
]
}
const chart = echarts.init(document.getElementById(id));
chart.setOption(options);
},['optionsData'])
return (
<div id={id} style={{width: width, height: height}}>222</div>
)
}
import React,{useState} from 'react'
import ChartBar from './views/ChartBar'
export default function App() {
const [echarts,setEcharts]=useState({
xdata:['1月', '2月', '3月', '4月', '5月', '6月','7月','8月','9月','10月','11月','12月'],
ydata: [5, 20, 36, 10, 10, 20,89,100,22,56,78,99],
y2data: [15, 25, 46, 20, 20, 40,99,100,32,46,28,19]
})
return (
<div>
<ChartBar
id="chart-bar"
optionsData={echarts}
title={"某培训机构2021年全年招生"}
seriesName={"招生量"}
width={880}
height={600}></ChartBar>
</div>
)
}
4、饼形图的配置
4.1、基本配置
import React,{useEffect} from 'react'
import * as echarts from 'echarts';
export default function ChartBar(props) {
const {pieData = null, id = 'default-id', width = 600, height = 200,title="echart演示"} = props;
useEffect(()=>{
const options={
title:{
text:title
},
series: [
{
type: 'pie',
data: pieData,
}
]
}
const chart = echarts.init(document.getElementById(id));
chart.setOption(options);
},['optionsData'])
return (
<div id={id} style={{width: width, height: height}}>222</div>
)
}
import React, { useState } from 'react'
import ChartBar from './views/ChartBar'
export default function App() {
const [echarts, setEcharts] = useState(
[
{ name:"吃饭",value: 1321},
{ name:"旅游",value:123},
{name:"交通",value:671},
{name:"购买书籍",value:2345},
{name:"买衣服",value:67}
])
return (
<div>
<ChartBar
id="chart-bar"
pieData={echarts}
title={"全年消费情况"}
width={880}
height={600}></ChartBar>
</div>
)
}
4.2、常见效果设置
const options={
title:{
text:title
},
series: [
{
type: 'pie',
data: pieData,
label:{
show:true,
formatter:function(arg){
return arg.name+'部分消费了'+arg.value+'元\n'+arg.percent+'%'
}
},
//radius:['60%','80%'],
roseType:'radius',
selectedMode:'single'
}
]
}
八、React.memo和useCallback
1、React.memo
React.memo 可以用来缓存组件。
在 React 中,默认情况下,父组件更新时,无论子组件内部是否改变,子组件也会更新。
但是,从性能考虑,我们希望的是:父组件更新时,如果子组件内部(state 和 props)没有发生改变,子组件不用更新。
解决方法,就是用
React.memo
将子组件缓存起来。
import {useState} from 'react'
import HookChild from './HookChild'
export default function HookParent() {
console.log('父组件');
const [count,setCount]=useState(0)
return (
<div>
<h1>父组件:{count}</h1>
<button onClick={()=>setCount(count+1)}>+1</button>
<HookChild></HookChild>
</div>
)
}
import React from 'react'
function HookChild() {
console.log('子组件');
return (
<h2>子组件</h2>
)
}
export default React.memo(HookChild);
2、useCallback
useCallback 可以用来缓存函数。
2.1、基础语法
import { useCallback } from 'react';
const 变量名 = useCallback(缓存的函数, [])
2.2、应用场景
通常,我们为了减少子组件不必要的更新,会使用
React.memo()
来缓存子组件的状态。
但是,如果父组件传递了函数给子组件,那么,每次父组件更新时,函数都会重新创建。子组件中的
React.memo()
就会判定为父组件传递的内容发生了改变,那么
React.memo()
就不会缓存当前子组件的状态。
因此,为了解决函数的问题,我们需要保存函数的状态,让父组件更新时函数能够缓存下来,因此我们需要使用
useCallback
将传递的子组件的函数状态缓存起来。
import { useCallback, useState } from "react";
import HookChild from "./HookChild";
export default function HookFather() {
console.log('父组件');
const [count, setCount] = useState(0);
const sayHello = () => {
console.log('hello');
}
// 缓存函数状态
const cbSayHello = useCallback(sayHello, []);
return (
<>
<h1>父组件:{count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
<HookChild sayHello={cbSayHello}></HookChild>
</>
)
}
import React from 'react'
function HookChild({sayHello}) {
console.log('子组件');
return (
<div>
<h2>子组件</h2>
</div>
)
}
export default React.memo(HookChild)
九、自定义hook
自定义hook提取函数组件公共逻辑
- 自定义hook的作用在于提取公共逻辑,所以一般不会返回一个JSX对象,而是会根据需要返回特定的数据或者方法
- 自定义hook必须要以use开头
假设现在有Test1和Test2两个函数组件,他们有一些公共逻辑需要提取,比如都要从后台获取一个列表数据,然后用户界面的渲染,则现在可以编写一个自定义hook来提取这部分公共逻辑,以避免重复写代码
import {useState,useEffect} from 'react'
export default function useData(){
const [list,setList] = useState([]);
useEffect(()=>{setTimeout(()=>{
const list = [1,2,3]
setList(list);
},200);},[]);
return {list,}}
//Test1
import useData from '...'
function Test1(){
const {list} = useData();
return
div>
{...用list渲染JSX}
</div>
}
//Test2类似
版权归原作者 张大爷爱遛弯 所有, 如有侵权,请联系我们删除。