react基础
用react脚手架创建项目
npx create-react-app my-app
然后打开app.js文件,删除多余部分
function App() {
return (
<div >
<h1>hello react</h1>
</div>
);
}
export default App;
JSX
在学习如何操作之前,先要了解一下JSX语法,想app.js里面像JavaScript又像html一样的语法就是JSX,上面写法的一些基本规则
1,有且只有一个根元素
2,class要用className
3,style的格式为style={{属性:值}},属性要用小驼峰命名
4,可以插入值,用{}
const No = {
name: '不忘',
age: '19'
}
function App() {
return (
<div >
<h1>hello react</h1>
<p>{No.name}有很多老婆,今年{No.age}了</p>
<ul>
</div>
);
}
export default App;
5,也可以加入一些表达式
const No = {
name: '不忘',
age: '19',
girlfriend:['冰冰','嘉嘉','琳琳']
}
function App() {
return (
<div >
<h1>hello react</h1>
<p>{No.name}有很多老婆,今年{No.age}了</p>
<ul>
<li>女朋友有:</li>
{
No.girlfriend.map((value,index)=>{
return <li key={index}>{value}</li>
})
}
</ul>
{
No.age>18? <h1>准备结婚了</h1> : <h1>等成年就结婚</h1>
}
</div>
);
}
export default App;
6.标签小写开头会转换为html标签,大写开头会转换成组件
function App() {
return (
<div >
<h1>hello react</h1>
<Dream />
</div>
);
}
function Dream() {
return (
<h2>做人如果没用梦想,那和咸鱼有什么区别</h2>
)
}
export default App;
组件
函数式组件
function App() {
return (
<div >
<h1>hello react</h1>
</div>
);
}
类组件
class App extends React.Component{
render() {
return (
<div>
<h1>hello</h1>
</div>
);
};
};
注意组件名首字母大写
组件实例三大属性
state
基础
class App extends React.Component{
constructor(props) {
super(props);
this.state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
}
render() {
return (
<div>
<h1>hello</h1>
<h2>{this.state.msg}</h2>
</div>
);
};
};
优化一点
class App extends React.Component{
constructor(props) {
super(props);
this.state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
}
render() {
const {msg} = this.state;
return (
<div>
<h1>hello</h1>
<h2>{msg}</h2>
</div>
);
};
};
修改state
涉及事件调用,看到目录点击事件
class App extends React.Component{
constructor(props) {
super(props);
this.state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。',show: true}
this.change=this.change.bind(this)
}
render() {
const {msg,show} = this.state;
return (
<div>
<h1>hello</h1>
<button onClick={this.change}>{!show? '出现':'消失'}</button>
<h2>{show? msg :''}</h2>
</div>
);
};
change(){
this.setState({show: !this.state.show});//知道修改state要调用setState就好了
}
};
优化
class App extends React.Component{
state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。',show: true}
render() {
const {msg,show} = this.state;
return (
<div>
<h1>hello</h1>
<button onClick={this.change}>{!show? '出现':'消失'}</button>
<h2>{show? msg :''}</h2>
</div>
);
};
change=() => {
this.setState({show: !this.state.show});//知道修改state要调用setState就好了
}
};
props
基础用法
class App extends React.Component{
render() {
return (
<div >
<Dream name="不忘" girlfriend="冰冰"/>
<br/>
<br/>
<Dream name="回忆" girlfriend="翠花"/>
</div>
);
};
};
class Dream extends React.Component{
render() {
return (
<div>
<h1>hello {this.props.name}</h1>
<h2>你的老婆{this.props.girlfriend}来了</h2>
</div>
);
};
};
优化
class App extends React.Component{
render() {
const no={name: "不忘",girlfriend:'冰冰'}
const yes={name: "回忆", girlfriend:'翠花'}
return (
<div >
<Dream {...no}/>
<br/>
<br/>
<Dream {...yes}/>
</div>
);
};
};
class Dream extends React.Component{
render() {
const {name,girlfriend}=this.props;
return (
<div>
<h1>hello {name}</h1>
<h2>你的老婆{girlfriend}来了</h2>
</div>
);
};
};
props限制
react@15.5版本以上
下包
npm i prop-types --save
导入
import PropTypes from 'prop-types';
使用
class App extends React.Component{
render() {
const no={name: "不忘",girlfriend:'冰冰'}
const yes={name: "回忆", girlfriend:'翠花'}
return (
<div >
<Dream {...no}/>
<br/>
<br/>
<Dream {...yes}/>
</div>
);
};
};
function Dream(props) {
const {name,girlfriend,msg}=props;
return (
<div>
<h1>hello {name}</h1>
<h2>你的老婆{girlfriend}来了</h2>
<p>{msg}</p>
</div>
);
};
Dream.propTypes={
name: PropTypes.string,
}
Dream.defaultProps={
msg:'开心的跳了起来'
}
优化
class App extends React.Component{
render() {
const no={name: "不忘",girlfriend:'冰冰'}
const yes={name: "回忆", girlfriend:'翠花'}
return (
<div >
<Dream {...no}/>
<br/>
<br/>
<Dream {...yes}/>
</div>
);
};
};
class Dream extends React.Component{
static propTypes = {//限制类型
name: PropTypes.string,
}
static defaultProps = {//设置默认值
msg:'开心的跳了起来'
}
render() {
const {name,girlfriend,msg}=this.props;
return (
<div>
<h1>hello {name}</h1>
<h2>你的老婆{girlfriend}来了</h2>
<p>{msg}</p>
</div>
);
};
};
常用的限制有
数组:array
布尔:bool
函数:func
数字:number
对象:object
字符串:string
函数式组件的props
class App extends React.Component{
render() {
const no={name: "不忘",girlfriend:'冰冰'}
const yes={name: "回忆", girlfriend:'翠花'}
return (
<div >
<Dream {...no}/>
<br/>
<br/>
<Dream {...yes}/>
</div>
);
};
};
function Dream(props) {
const {name,girlfriend,msg}=props;
return (
<div>
<h1>hello {name}</h1>
<h2>你的老婆{girlfriend}来了</h2>
<p>{msg}</p>
</div>
);
};
refs
能少用就少用
字符串ref(最好不用)
class App extends React.Component{
showData=()=>{
const {data} = this.refs;
console.log(data.value);
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" ref="data" name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
回调函数ref
class App extends React.Component{
showData=()=>{
const {data} = this;
console.log(data.value);
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" ref={value=>this.data=value} name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
类绑定
class App extends React.Component{
showData=()=>{
const {data}=this;
console.log(data.value);
}
saveInput=(value)=>{
this.data=value;
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" ref={this.saveInput} name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
cractRef(推荐)
class App extends React.Component{
saveRef=React.createRef()
showData=()=>{
console.log(this.saveRef.current.value);
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" ref={this.saveRef} name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
事件
事件名用onXxxx,on后面第一个字母大写
委托的方式挂载在外最外层元素上
可以通过event.target获取发生对象的dom
class App extends React.Component{
showData=(event) =>{
console.log(event.target.value);
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
获取参数
在获取参数前先了解一个概念叫函数柯里化
调用的函数参数在返回发函数中统一处理的方式叫函数柯里化
class App extends React.Component{
state={msg:'',find:''}
showData=(data) =>{
return (event)=> {
this.setState({[data]:event.target.value});
this.setState({msg:data});
}
}
render() {
const {msg,find} = this.state
return (
<div >
<input onChange={this.showData('find')} type="text" name="" id="" placeholder="输入查询内容"/>
<h1>{msg}</h1>
<p>{find}</p>
</div>
);
};
};
不用柯里化
class App extends React.Component{
state={msg:'',find:''}
showData=(data,event) =>{
this.setState({[data]:event.target.value});
this.setState({msg:data});
}
render() {
const {msg,find} = this.state
return (
<div >
<input onChange={(event)=>this.showData('find',event)} type="text" name="" id="" placeholder="输入查询内容"/>
<h1>{msg}</h1>
<p>{find}</p>
</div>
);
};
};
受控组件,非受控组件
简单讲就是有木有state保存数据
非受控组件
class App extends React.Component{
showData=(event) =>{
console.log(event.target.value);
}
render() {
return (
<div >
<input onBlur={this.showData} type="text" name="" id="" placeholder="输入查询内容"/>
</div>
);
};
};
受控组件
class App extends React.Component{
state={msg:''}
showData=(event) =>{
this.setState({msg:event.target.value});
}
render() {
const {msg} = this.state
return (
<div >
<input onChange={this.showData} type="text" name="" id="" placeholder="输入查询内容"/>
<h1>{msg}</h1>
</div>
);
};
};
组件生命周期
简单演示新的生命周期函数,有三种情况
初始化阶段
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
constructor(props) {
super(props);
this.state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
}
render() {
return (
<div>
<h1>hello</h1>
<div id="children">
<Children msg={this.state.msg}/>
</div>
</div>
);
};
};
class Children extends Component{
constructor(props) {
console.log('constructor');
super(props);
this.state={}
}
static getDerivedStateFromProps(props,state) {
console.log('getDerivedStateFromProps',props,state);
return props //将state的值转换成接受的props,返回unll不发送改变
}
componentDidMount(){
console.log('componentDidMount');//一般写组件一开始就出现的功能,网络加载,定时器等等
}
render() {
console.log('render');
return (
<div>
<h2>{this.state.msg}</h2>
<h2>{this.props.msg}</h2>
</div>
);
};
};
export default App;
更新阶段
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
constructor(props) {
super(props);
this.state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
}
render() {
return (
<div>
<h1>hello</h1>
<div id="children">
<Children msg={this.state.msg}/>
</div>
</div>
);
};
};
class Children extends Component{
state={mage:''}
static getDerivedStateFromProps(props,state){
console.log('getDerivedStateFromProps',props,state);
return null
}
shouldComponentUpdate(){
console.log('shouldComponentUpdate');
return true
//返回true更新,返回false不更新
}
getSnapshotBeforeUpdate(preProps,preState){
console.log('getSnapshotBeforeUpdate',preProps,preState);
return '来自getSnapshotBeforeUpdate的值'
//即将更新,可以获取更新前的数据,返回的值都会被componentDidUpdate接收
}
componentDidUpdate(preProps,preState,val){
console.log('componentDidUpdate',preProps,preState,val);
//变化前的props,state和来自getSnapshotBeforeUpdate的返回值
}
change=()=> {
this.setState({msge:'寒来暑往,秋收冬藏。闰余成岁,律吕调阳'})
}
render() {
console.log('render');
return (
<div>
<h2>{this.props.msg}</h2>
<h2>{this.state.msge}</h2>
<button onClick={this.change}>改变</button>
</div>
);
};
};
export default App;
卸载组件
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
state = {msg: '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
componentWillMount() {
console.log('componentWillMount');//卸载前执行
}
remove=() => {
ReactDOM.unmountComponentAtNode(document.getElementById('root'));//卸载组件
}
render() {
return (
<div>
<h1>hello</h1>
<h2>{this.state.msg}</h2>
<button onClick={this.remove}>卸载</button>
</div>
);
};
};
export default App;
diffing算法
diffing算法是用来对比虚拟dom和真实dom的,当虚拟dom发生改变时,将真实dom不同的部分进行修改
虚拟dom中key是虚拟dom的唯一标识,对比key相同的元素,如果不同改变真实dom的内容,如果真实dom没用虚拟dom的key的元素,就会创建对应的元素
当用index作为key时,逆序的添加删除等破坏顺序的操作会影响效率
如果包含输入内的dom就会发生错误
class App extends React.Component{
state={data:[
{name:'不忘',age:20},
{name:'回忆',age:18},
]}
add=()=>{
this.setState({data: [
{name:'留念',age:19},
{name:'不忘',age:20},
{name:'回忆',age:18},
]})
}
render() {
const {data} = this.state
return (
<div >
<button onClick={this.add}>添加</button>
{
data.map(val=>{
return (
<h1>{val.name}牛逼,今年{val.age} <input type="text"/></h1>
)
})
}
</div>
);
};
};
//当在输入框内输入内容然后点击增加,就会发现输入框和前面的值不对应了
代理服务器配置
在src下创建setupProxy.js
const { proxy } = require('http-proxy-middleware')
// 或
// const proxy = require('http-proxy-middleware')
module.exports = function (app) {
app.use(proxy('/api', {
target: 'http://172.16.136.249:8080',
secure: false,
changeOrigin: true,
pathRewrite: {
"^/api": "/api"
}
}))
}
路由(dom)
基础使用
下载包
npm i react-router-dom
打开index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from 'react-router-dom';
//导入BrowserRouter,作为组件嵌套App组件,使用history模式,所有还有HasRouter对应hash模式
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
打开App.js
import React from 'react';
import {Link,Route} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
class App extends React.Component{
render() {
return (
<div >
<Link to="/no" >不忘的老婆</Link>
{/*Link组件设置点击跳转的路径,to是跳转的路径*/}
<br/>
<Link to="/yes" >回忆的老婆</Link>
<br/>
<Route path="/no" component={no}/>
{/*Route设置跳转的内容,path是跳转的路径,component是跳转的内容*/}
<Route path="/yes" component={yes}/>
</div>
);
};
};
export default App;
创建index文件夹,创建no.jsx和yes.jsx
no.jsx
import React from 'react';
export class no extends React.Component{
render() {
return (
<div>
<h1>冰冰</h1>
</div>
);
};
};
yes.jsx
import * as React from 'react';
export class yes extends React.Component{
render() {
return (
<div>
<h1>如花</h1>
</div>
);
};
};
路由组件
像上面那样的no.jsx和yes.jsx就属于路由组件
看看路由组件的props的有固定的属性
history
localtion
matchactive
NavLink
前面有用过Link组件,和他的区别就是,当你点击是会自动添加一个active的类名,如果你自定义了一个类名activeClassName,也会在点击时自动添加上,点击别的NavLink是自动清除
修改App.js
import React from 'react';
import './App.css'
import {NavLink,Route} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
</div>
);
};
};
export default App;
修改App.css
.active{
color: red;
}
.ch{
font-size: 30px;
}
Switch
当匹配到对应路由后就不会再向下匹配
修改App.js
import React from 'react';
import './App.css'
import {NavLink,Route,Switch} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<Switch>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
</Switch>
</div>
);
};
};
export default App;
模糊匹配
就说当路由相同时,后面多几个子路由依然会获取当前路由的信息
import React from 'react';
import './App.css'
import {NavLink,Route,Switch} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no/suiyi" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<Switch>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
</Switch>
</div>
);
};
};
export default App;
开启精准匹配,就需要路由一模一样的
import React from 'react';
import './App.css'
import {NavLink,Route,Switch} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<Switch>
<Route exact path="/no" component={no}/>
{/*exact开启精准匹配*/}
<Route path="/yes" component={yes}/>
</Switch>
</div>
);
};
};
export default App;
Redirect
当路由都匹配不上时就会去redirect
import React from 'react';
import './App.css'
import {NavLink,Route,Switch,Redirect} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
import {noFind} from './index/nofind'
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/nover" >你的老婆</NavLink>
<br/>
<Switch>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
<Route path="/notFind" component={noFind}/>
<Redirect to="/notFind"/>
{/*重定向到notFind路径*/}
</Switch>
</div>
);
};
};
export default App;
路由嵌套
打开no.jsx
import React from 'react';
import {Link,Route} from 'react-router-dom'
import binbin from './noGirl/binbin'
import jiajia from './noGirl/jiajia'
export class no extends React.Component{
render() {
return (
<div>
<Link to="/no/binbin" className="next">冰冰</Link>
<Link to="/no/jiajia" className="next">嘉嘉</Link>
{/*路径的名字要加上父路由的内容*/}
<Route path="/no/binbin" component={binbin}/>
<Route path="/no/jiajia" component={jiajia}/>
</div>
);
};
};
创建noGirl文件夹,然后创建binbin.jsx和jiajia.jsx
binbin.jsx
import React, { Component } from 'react';
class binbin extends Component {
render() {
return (
<div>
<p>性格</p>
<p>爱好</p>
<p>照片</p>
</div>
);
}
}
export default binbin;
jiajia.jsx
import React, { Component } from 'react';
class jiajia extends Component {
render() {
return (
<div>
<p>身高</p>
<p>体重</p>
<p>年龄</p>
</div>
);
}
}
export default jiajia;
带参数路由
params传参
先看no.jsx
import React from 'react';
import {Link,Route} from 'react-router-dom'
import girl from './girl'
export class no extends React.Component{
render() {
return (
<div>
<Link to="/no/1" className="next">第一个老婆</Link>
<Link to="/no/2" className="next">第二个老婆</Link>
{/*在后面加入参数*/}
<Route path="/no/:id" component={girl}/>
{/*用/:参数/:参数的形式传递*/}
</div>
);
};
};
然后修改girl.jsx
import React, { Component } from 'react';
class girl extends Component {
state={girl:[
{id:1,name: "冰冰"},
{id:2,name: "嘉嘉"}
]}
render() {
let {girl}=this.state;
const {id}=this.props.match.params;
//在this.props.match.params接收
const c=girl.find(value => {
return value.id===id-0
})
return (
<div>
<h1>
{c.name}
</h1>
</div>
);
}
}
export default girl;
serch传参
修改no.jsx
import React from 'react';
import {Link,Route} from 'react-router-dom'
import girl from './girl'
export class no extends React.Component{
render() {
return (
<div>
<Link to="/no/?id=1&msg=非常好看" className="next">第一个老婆</Link>
<Link to="/no/?id=2&msg=非常可爱" className="next">第二个老婆</Link>
{/*用?属性=值&属性=值的方式传递*/}
<Route path="/no" component={girl}/>
</div>
);
};
};
修改girl.jsx
import React, { Component } from 'react';
import qs from 'querystring'
class girl extends Component {
state={girl:[
{id:1,name: "冰冰"},
{id:2,name: "嘉嘉"}
]}
render() {
let {girl}=this.state;
const {search}=this.props.location;
{/*接收参数*/}
const data=qs.parse(search);
{/*变成对象*/}
const c=girl.find(value => {
return value.id===data['?id']-0
})
console.log(data['?id']);
return (
<div>
<h1>
{c.name}
</h1>
<p>{data.msg}</p>
</div>
);
}
}
export default girl;
state传参
修改no.jsx
import React from 'react';
import {Link,Route} from 'react-router-dom'
import girl from './girl'
export class no extends React.Component{
render() {
return (
<div>
<Link to={{pathname:'/no',state:{id:1,msg:'非常好看'}}} className="next">第一个老婆</Link>
<Link to={{pathname:'/no',state:{id:2,msg:'非常可爱'}}} className="next">第二个老婆</Link>
<Route path="/no" component={girl}/>
</div>
);
};
};
修改girl.jsx
import React, { Component } from 'react';
import qs from 'querystring'
class girl extends Component {
state={girl:[
{id:1,name: "冰冰"},
{id:2,name: "嘉嘉"}
]}
render() {
let {girl}=this.state;
const {id,msg}=this.props.location.state || {};
const c=girl.find(value => {
return value.id===id-0
}) || {}
return (
<div>
<h1>
{c.name}
</h1>
<p>{msg}</p>
</div>
);
}
}
export default girl;
push和replace
push会留下历史记录,能够返回,replace没有记录,不能返回
打开app.js
import React from 'react';
import './App.css'
import {NavLink,Route,Switch,Redirect} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
import {noFind} from './index/nofind'
class App extends React.Component{
render() {
return (
<div >
<NavLink replace activeClassName="ch" to="/no" >不忘的老婆</NavLink>
{/*replace开启路由*/}
<br/>
<NavLink replace activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<NavLink replace activeClassName="ch" to="/nover" >你的老婆</NavLink>
<br/>
<Switch>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
<Route path="/notFind" component={noFind}/>
<Redirect to="/notFind"/>
</Switch>
</div>
);
};
};
export default App;
编程式导航
将路由跳转用函数打方式实现
打开no.jsx
import React from 'react';
import {Link,Route} from 'react-router-dom'
import girl from './girl'
export class no extends React.Component{
go=() => {
// this.props.history.push('/no/1')
// this.props.history.push('/no/?id=1')
this.props.history.push('/no/',{id:1,msg:'好看'})
// this.props.history.replace('/no/1')
// this.props.history.replace('/no/?id=1')
// this.props.history.replace('/no/',{id:1})
// this.props.history.goBack()//后退
// this.props.history.goForward()//前进
// this.props.history.go()//正数向前跳几页,负数向后跳几页
}
goer=() => {
this.props.history.push('/no/',{id:2,msg:'可爱'})
}
render() {
return (
<div>
<h1 onClick={this.go}>第一个老婆</h1>
<h1 onClick={this.goer}>第二个老婆</h1>
<Route path="/no" component={girl}/>
</div>
);
};
};
weithRouter
一般组件没有办法使用编程式导航,这是可以用withRouter
打开App.js
import React from 'react';
import './App.css'
import {NavLink,Route,Switch,Redirect, withRouter} from 'react-router-dom';
import {no} from './index/no.jsx'
import {yes} from './index/yes'
import {noFind} from './index/nofind'
class App extends React.Component{
render() {
return (
<div >
<NavLink replace activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink replace activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<NavLink replace activeClassName="ch" to="/nover" >你的老婆</NavLink>
<br/>
<Switch>
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
<Route path="/notFind" component={noFind}/>
<Redirect to="/notFind"/>
</Switch>
</div>
);
};
};
export default withRouter(App);
//这里导出时用withRouter生成新的组件,可以拥有路由组件的api
BrowserRouter和HashRouter的区别
底层原理,BrowserRouter使用h5的history,不兼容ie9以下,HashRouter使用哈希值
路径的样子不一样HashRouter的路由中间隔一个#
HashRouter使用state传参刷新后数据会丢失
redux
下包
npm i redux
npm i redux-thunk //支持异步
基本使用,异步也比较少用
修改app.js
import React, { Component } from 'react';
import store from './redux/store';
import {add,less,addAsync} from './redux/action';
class App extends Component {
state={}
add=()=>{
store.dispatch(add(1))
}
less=()=>{
store.dispatch(less(1))
}
addAsync=()=>{
store.dispatch(addAsync(1,1000))
}
componentDidMount() {
}
render() {
return (
<div>
和:{store.getState()}
<ul>
<li><button onClick={this.add}>加</button></li>
<li><button onClick={this.less}>减</button></li>
<li><button onClick={this.addAsync}>异步加</button></li>
</ul>
</div>
);
}
}
export default App;
修改index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
store.subscribe(()=>{
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
})
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
创建redux文件夹
在下面创建store.js
import {createStore,applyMiddleware} from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
export default createStore(reducer,applyMiddleware(thunk))
创建reducer.js
import {ADD,LESS} from './constant'
const firstState=0
export default function count(preState=firstState,action){
const {type,data} = action;
switch(type){
case ADD:
return preState+data
case LESS:
return preState-data
default:
return preState
}
}
创建action.js
import {ADD,LESS} from './constant'
export const add=data=>({type:ADD, data})
export const less=data=>({type:LESS, data})
export const addAsync=(data,time)=>{
return (dispatch)=>{
setTimeout(()=>{
dispatch(add(data))
},time)
}
}
创建constant.js
export const ADD='add'
export const LESS='less'
react-redux
下包
npm i react-redux
修改app.js
import React, { Component } from 'react';
import Son from './son'
class App extends Component {
render() {
return (
<div>
<Son/>
</div>
);
}
}
export default App;
创建son.js
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {add,less,addAsync} from './redux/count_action'
class Son extends Component {
state={}
add=()=>{
this.props.add(1)
}
less=()=>{
this.props.less(1)
}
addAsync=()=>{
this.props.addAsync(1,500)
}
render() {
return (
<div>
和:{this.props.total}
<ul>
<li><button onClick={this.add}>加</button></li>
<li><button onClick={this.less}>减</button></li>
<li><button onClick={this.addAsync}>异步加</button></li>
</ul>
</div>
);
}
}
export default connect(
state=> ({total:state}),//传递状态
{
add,
less,
addAsync,
} //操作状态的方法
)(Son)
修改index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
共享数据
创建otherSon.js
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {add,less,addAsync} from './redux/action'
class otherSon extends Component {
state={}
add=()=>{
this.props.add(1)
}
less=()=>{
this.props.less(1)
}
addAsync=()=>{
this.props.addAsync(1,500)
}
render() {
return (
<div>
和:{this.props.all}
<ul>
<li><button onClick={this.add}>加</button></li>
<li><button onClick={this.less}>减</button></li>
<li><button onClick={this.addAsync}>异步加</button></li>
</ul>
</div>
);
}
}
export default connect(
state=> ({all:state.othercount}),//传递状态
{
add,
less,
addAsync,
} //操作状态的方法
)(otherSon)
共享值
在创建一个otherson.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {adda,lessa,addAsynca} from './redux/action'
class otherSon extends Component {
state={}
adda=()=>{
this.props.adda(1)
}
lessa=()=>{
this.props.lessa(1)
}
addAsynca=()=>{
this.props.addAsynca(1,500)
}
render() {
return (
<div>
和:{this.props.all}
<ul>
<li><button onClick={this.adda}>加</button></li>
<li><button onClick={this.lessa}>减</button></li>
<li><button onClick={this.addAsynca}>异步加</button></li>
</ul>
</div>
);
}
}
export default connect(
state=> ({all:state.othercount}),//传递状态
{
adda,
lessa,
addAsynca,
} //操作状态的方法
)(otherSon)
修改son.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {add,less,addAsync} from './redux/action'
class Son extends Component {
state={}
add=()=>{
this.props.add(1)
}
less=()=>{
this.props.less(1)
}
addAsync=()=>{
this.props.addAsync(1,500)
}
render() {
return (
<div>
和:{this.props.total}
<ul>
<li><button onClick={this.add}>加</button></li>
<li><button onClick={this.less}>减</button></li>
<li><button onClick={this.addAsync}>异步加</button></li>
</ul>
</div>
);
}
}
export default connect(
state=> ({total:state.count}),//传递状态
{
add,
less,
addAsync,
} //操作状态的方法
)(Son)
修改store.js
import {createStore,applyMiddleware,combineReducers} from 'redux'
import count from './reducer'
import othercount from './other_count'
import thunk from 'redux-thunk'
const all=combineReducers({
count,
othercount
})
export default createStore(all,applyMiddleware(thunk))
创建other_count.js
import {ADDA,LESSA} from './constant'
const firstState=0
export default function count(preState=firstState,action){
const {type,data} = action;
switch(type){
case ADDA:
return preState+data
case LESSA:
return preState-data
default:
return preState
}
}
修改action.js
import {ADD,LESS,ADDA,LESSA} from './constant'
export const add=data=>({type:ADD, data})
export const less=data=>({type:LESS, data})
export const addAsync=(data,time)=>{
return (dispatch)=>{
setTimeout(()=>{
dispatch(add(data))
},time)
}
}
export const adda=data=>({type:ADDA, data})
export const lessa=data=>({type:LESSA, data})
export const addAsynca=(data,time)=>{
return (dispatch)=>{
setTimeout(()=>{
dispatch(adda(data))
},time)
}
}
修改constant.js
export const ADD='add'
export const LESS='less'
export const ADDA='adda'
export const LESSA='lessa'
扩展
setState
两种写法
第一种,对象式
import React, { Component } from 'react';
class App extends Component {
state={name:'冰冰'};
change=()=>{
this.setState({name:this.state.name+',嘉嘉'},()=>{
console.log(this.state.name);//冰冰,嘉嘉
});
console.log(this.state.name);//冰冰
}
render() {
return (
<div>
<h1>不忘的老婆是{this.state.name}</h1>
<button onClick={this.change}>真实情况</button>
</div>
);
}
}
export default App;
第二种,编程式
import React, { Component } from 'react';
class App extends Component {
state={name:'冰冰'};
change=()=>{
this.setState(state=>({name:state.name+',嘉嘉'}),()=>{
console.log(this.state.name);//冰冰,嘉嘉
});
console.log(this.state.name);//冰冰
}
render() {
return (
<div>
<h1>不忘的老婆是{this.state.name}</h1>
<button onClick={this.change}>真实情况</button>
</div>
);
}
}
export default App;
lazy
懒加载,按需加载
import React,{lazy,Suspense} from 'react';
import './App.css'
import {NavLink,Route} from 'react-router-dom';
const no=lazy(()=> import('./index/no.jsx'));
const yes=lazy(()=> import('./index/yes.jsx'));
class App extends React.Component{
render() {
return (
<div >
<NavLink activeClassName="ch" to="/no" >不忘的老婆</NavLink>
<br/>
<NavLink activeClassName="ch" to="/yes" >回忆的老婆</NavLink>
<br/>
<Suspense fallback={<h1>等待。。。。</h1>} >
<Route path="/no" component={no}/>
<Route path="/yes" component={yes}/>
</Suspense>
</div>
);
};
};
export default App;
hooks
state hooks
使函数组件能保存数据
import React, { Component } from 'react';
function App() {
const [name,setNmae]=React.useState('冰冰')
function change(){
// setNmae(name+',嘉嘉');
setNmae(name=>name+',嘉嘉');
}
return (
<div>
<h1>不忘的老婆是{name}</h1>
<button onClick={change}>真实情况</button>
</div>
)
}
export default App;
effect hooks
相当于生命周期函数
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
const [num,add]=React.useState(0)
React.useEffect(() => {
let timer=setInterval(() => {
add(num=>num+1);
},1000)
return ()=>{
clearInterval(timer)//消失前执行
}
},[])//第二个参数监听改变的数据,开始就会加载一次
function remove() {
ReactDOM.unmountComponentAtNode(document.getElementById("root"))
}
return (
<div>
<h1>自加一:{num}</h1>
<button onClick={remove}>卸载</button>
</div>
)
}
export default App;
ref hooks
函数式组件获取ref
import React from 'react';
function App() {
const myInput=React.useRef()
function getVal(){
console.log(myInput.current.value);
}
return (
<div>
<input type="text" ref={myInput}/>
<button onClick={getVal}>查看内容</button>
</div>
)
}
export default App;
Fragment
去掉最外面的根元素,防止嵌套太多
import React,{Fragment} from 'react';
function App() {
return (
<Fragment key={1}>
{/*可以添加唯一标识key*/}
<h1>潜龙勿用</h1>
</Fragment>
)
}
export default App;
Context
祖孙之前传值
import React, { Component } from 'react';
const MyContext=React.createContext()//
const {Provider,Consumer} = MyContext;//
class App extends Component {
state={name:'回忆',age:18}
render() {
const {name, age} = this.state;
return (
<div>
不忘爸爸
<Provider value={{name,age}}>
{/*包裹传值*/}
<Children />
</Provider>
</div>
);
}
}
class Children extends Component {
render() {
return (
<div>
儿子
<GChild />
</div>
);
}
}
//类组件
// class GChild extends Component {
// static contextType = MyContext
// //接上context
// render() {
// const {name, age} = this.context;
// {/*获取值*/}
// return (
// <div>
// 孙子:{name}今年{age}了
// </div>
// );
// }
// }
//函数组件
function GChild() {
return (
<div>
孙子:
<Consumer>
{/*包裹*/}
{
value=>{
//值就在value中
return value.name+'今年'+value.age+'了'
}
}
</Consumer>
</div>
)
}
export default App;
组件优化
pureComponent
当父组件更新时,子组件也会更新,当setState执行,数据不改变时,也会更新,这样会浪费性能
可以设置shouldComponent,判断前后数据是否相同
也可以使用pureComponent
import React, { PureComponent } from 'react';
class App extends PureComponent {
state={Fname:'不忘'}
change=()=>{
this.setState({})
}
render() {
const {Fname} = this.state;
console.log('father--render');
return (
<div>
{Fname}爸爸
<Children />
<button onClick={this.change}>改变</button>
</div>
);
}
}
class Children extends PureComponent {
render() {
console.log('children--render');
return (
<div>
儿子
</div>
);
}
}
export default App;
注意内部是浅比较,当数据变化,但用的是同一个对象或者数组时,也不会更新数据
render Props
组件的另外一种套子组件的方式,类似于vue的插槽
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
不忘爸爸
<Children>
<GChild />
</Children>
</div>
);
}
}
class Children extends Component {
render() {
return (
<div>
儿子
{this.props.children/*这里就可以显示Children包裹的内容*/}
</div>
);
}
}
class GChild extends Component {
render() {
return (
<div>
孙子
</div>
);
}
}
export default App;
但这样不能传值,所有有了升级版renderProps
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
不忘爸爸
<Children render={(name)=>(<GChild name={name}/>)}/>
</div>
);
}
}
class Children extends Component {
state ={name: '回忆'};
render() {
return (
<div>
儿子
{this.props.render(this.state.name)}
</div>
);
}
}
class GChild extends Component {
render() {
return (
<div>
孙子:{this.props.name}
</div>
);
}
}
export default App;
错误边界
如果字组件错误,可以不影响页面的正常运行,将错误限制在组件内部,将bug提交查看
import React, { Component } from 'react';
class App extends Component {
state={error:''}
static getDerivedStateFromError(err) {
return {error:true};
}
componentDidCatch(err,info) {
console.log(err,info);
//统计错误次数发送给服务器,方便bug解决
}
render() {
return (
<div>
不忘爸爸
{!this.state.error ? '发生错误': <Children/> }
</div>
);
}
}
class Children extends Component {
state ={man:[
{id:1,name:'不忘'},
{id:2,name:'回忆'}
]};
render() {
return (
<div>
儿子
{this.state.man}
</div>
);
}
}
export default App;
组件传值
1.props
2.消息订阅-发布(pubs-sub等等)
下载包
yarn add pubus-js --sava
import React, { Component } from 'react';
import Pubsub from 'pubsub-js';//引入组件
class App extends Component{
render() {
return (
<div>
<h1>hello</h1>
<div id="children">
<Children />
<Childrene />
</div>
</div>
);
};
};
class Children extends Component{
state = {msg:'天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。'}
componentDidMount(){
Pubsub.subscribe('getMsg',(_,data)=>{//订阅消息
this.setState({msg:data});
})
}
render() {
return (
<div>
children:
<h2>{this.state.msg}</h2>
</div>
);
};
};
class Childrene extends Component{
state={msg:'道可道,非常道,名可名,非常名'}
give=()=>{
Pubsub.publish('getMsg',this.state.msg)//发布消息
}
render() {
return (
<div>
childrene:{this.state.msg}
<button onClick={this.give} >传递数据</button>
</div>
);
};
};
export default App;
3,集中管理(redux)
4。context(生产者-消费者模式)