React基础
hello world
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel"> // 此处一定要写babel
// 创建虚拟DOM
const VDOM = <h1>hello react</h1> //此处不要写引号,因为不是字符串
// 渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</body>
虚拟DOM的两种创建方式
- 使用 JS
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script type="text/javascript">
// 创建虚拟DOM
const VDOM = React.createElement('h1', {
id: 'title'
},
'Hello React'
)
// 渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</body>
- 使用 JSX
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel"> // 此处一定要写babel
// 创建虚拟DOM
const VDOM = (
<h1 id="title">hello react</h1> //此处不要写引号,因为不是字符串
)
// 渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</body>
JSX语法规则
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
const myId = "Tom"
const myData = 'hEllo reAct'
// 创建虚拟DOM
const VDOM = (
<h2 className="title" id={myId.toLowerCase()}>
<span style={{ color: 'blue', fontSize: '28px' }}>{myData.toLowerCase()}</span>
</h2>
)
// 渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'))
/**
* 1. 标签中混入`JS表达式`时,要使用 {}
* 2. 样式的类名指定不要用class, 要用className
* 3. 内联样式要用style={{key:value,key:value}}的形式去写
* 4. 只有一个根标签
* 5. 标签必须闭合
* 6. 标签首字母
* 1. 小写字母: html标签
* 2. 大写字母: 组件标签,若组件没有定义,就报错
*/
</script>
</body>
React中定义组件
- 函数式组件
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
// 创建函数式组件
function Demo() {
console.log(this); //undefined ,babel会开启严格模式,禁止this指向window
return <h2>我是函数式组件</h2>
}
// 渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
</script>
</body>
- 类式组件
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
//创建类式组件
class MyComponent extends React.Component{
// render放在了 MyComponent的原型对象上,供实例使用
//因此render中的this是 MyComponent组件实例对象
render() {
console.log('render中的this--->',this);
return <h2>我是类式组件</h2>
}
}
// 渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
</body>
组件实例三大属性之——state
- 复习:bind
<script>
function fun() {
console.log(this);
}
let x = fun.bind({ a: 1, b: 2 })
fun() //window
x() //{ a: 1, b: 2 }
</script>
- 复习:类中方法中this指向
<script>
// 类中所有方法都默认自动开启了局部严格模式
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
speak() {
//speak方法放在了类的原型对象上,供实例使用,通过Person实例调用speak时,speak中的this指向的是Person实例
console.log(this);
}
}
const p1 = new Person('tom', 12)
p1.speak() //通过实例调用speak方法
const x = p1.speak
// 当 x() 被调用时,输出的是 undefined,这是因为类方法中的 this 在非实例调用时,在严格模式下被绑定为 undefined。
x() //非实例调用
</script>
- 复杂写法
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
// 创建组件
class Weather extends React.Component {
// 构造器调用几次?----1次
constructor(props) {
super(props)
this.state = { isHot: true }
// 将原型上的changeWeather方法绑定this并赋值给实例对象上的changeWeather方法
this.changeWeather = this.changeWeather.bind(this)
}
// render调用几次?----1+n次,1是初始化的那次,n是状态更新的次数
render() {
// console.log(this);
// onclick要写onClick
return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
}
//changeWeather调用几次? 点几次,调几次
changeWeather() {
console.log('changeWeather被调用了');
// 由于changeWeather作为onClick的回调,不是通过实例对象调用的,而是直接调用,而且还由于类中的方法默认开启了严格模式,所以这里的this指向undefined
// 注意:state不可直接更改,要借助一个内置的API来更改
// this.state.isHot = !this.state.isHot //错误
// 注意:状态必须通过 setState进行更新
this.setState({ isHot: !this.state.isHot })
console.log(this.state.isHot);
console.log(this);
}
}
//渲染页面
ReactDOM.render(<Weather />, document.getElementById('test'))
</script>
</body>
- 简便写法
<body>
<div id="test">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
// 创建组件
class Weather extends React.Component {
// 初始化状态
state = { isHot: true }
render() {
console.log(this);
return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
}
// 自定义方法(赋值语句 + 箭头函数的形式)
changeWeather = () => {
this.setState({ isHot: !this.state.isHot })
}
}
//渲染页面
ReactDOM.render(<Weather />, document.getElementById('test'))
</script>
</body>
组件实例三大属性之——props
- 基础用法
<body>
<div id="test1">
</div>
<div id="test2">
</div>
<!-- 引入react -->
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../js/babel.min.js"></script>
<!-- 引入prop-types,用于对组件标签属性进行限制 -->
<script src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
render() {
const { name, age, sex } = this.props
// props是只读的
// this.props.name = 'king'
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
//对标签属性值进行类型和必要性的限制
Person.propTypes = {
// 从React16开始,PropTypes不再是在React中引入,而是在prop-types中引入
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.func // 必须是函数,不能用function,要用func
}
//指定默认的标签属性值
Person.defaultProps = {
sex: '不男不女',
age: 19
}
//渲染组件到页面
ReactDOM.render(<Person name="tom" age={18} sex="男" speak={speak} />, document.getElementById('test1'))
ReactDOM.render(<Person name="jerry" age={19} sex="男" />, document.getElementById('test1'))
const p = { name: '老刘' }
ReactDOM.render(<Person {...p} />, document.getElementById('test2'))
function speak() {
console.log('说话');
}
</script>
</body>
- 简写方式
<script type="text/babel">
//创建组件
class Person extends React.Component {
// 构造器是否接收props,是否传递给super,取决于是否希望在构造器中通过this访问props
// 开发中几乎不写构造器
constructor(props){
super(props)
console.log(this.props);
console.log(props);
}
//给类加属性,而不是给类的实例对象加属性,只需要在属性名前面加 static
static propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
}
static defaultProps = {
sex: '不男不女',
age: 19
}
render() {
const { name, age, sex } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name="tom" age={18} sex="男"/>, document.getElementById('test1'))
</script>
- 函数式组件使用props
<script type="text/babel">
// 函数式组件
function Person(props) {
const { name, age, sex } = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
}
Person.defaultProps = {
sex: '不男不女',
age: 19
}
//渲染组件到页面
ReactDOM.render(<Person name="tom" age={18} sex="男" />, document.getElementById('test1'))
</script>
组件实例三大属性之——refs
- 字符串形式的ref
<script type="text/babel">
// 创建组件
class Demo extends React.Component {
//展示左侧输入框的数据
showData = () => {
const { input1 } = this.refs
alert(input1.value)
}
showData2 = () => {
const { input2 } = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" />
<button onClick={this.showData}>点我提示左侧数据</button>
<input onBlur={this.showData2} ref="input2" type="text" placeholder="输入内容后请失去焦点" />
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
</script>
- 回调函数形式的ref
<script type="text/babel">
// 创建组件
class Demo extends React.Component {
//展示左侧输入框的数据
showData = () => {
const {input1} = this
alert(input1.value)
}
showData2 = () => {
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={c => this.input1 = c} type="text" />
<button onClick={this.showData}>点我提示左侧数据</button>
<input ref={c => this.input2 = c} onBlur={this.showData2} type="text" placeholder="输入内容后请手动失去焦点" />
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
</script>
- 回调ref中回调次数问题
<script type="text/babel">
// 创建组件
class Demo extends React.Component {
state = { isHot: true }
showInfo = () => {
const { input1 } = this
alert(input1.value)
}
changWeather = () => {
const { isHot } = this.state
this.setState({ isHot: !isHot })
}
//如果ref回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数null,第二次传入参数DOM元素
//这是因为在每次渲染时会创建一个新的函数实例,所以React清空旧的ref并设置新的
//定义成class的绑定函数,可以避免上述问题
saveInput = (c)=>{
this.input1 = c
console.log('@', c)
}
render() {
const { isHot } = this.state
return (
<div>
<h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
{/*jsx的注释方式*/}
{/*<input ref={(c) => { this.input1 = c; console.log('@', c); }} type="text" /><br/>*/}
<input ref={this.saveInput} type="text" />
<button onClick={this.showInfo}>点我</button>
<button onClick={this.changWeather}>点我切换天气</button>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
</script>
- createRef
<script type="text/babel">
// 创建组件
class Demo extends React.Component {
/*
React.createRef()调用后可以返回一个容器,该容器可以存储被ref所标识的节点
该容器是专人专用的,因此不能在多个组件间复用
*/
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = () => {
console.log(this.myRef.current.value);
alert(this.myRef.current.value)
}
showData2 = () => {
console.log(this.myRef2.current.value);
alert(this.myRef2.current.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" />
<button onClick={this.showData}>点我提示左侧数据</button>
<input onBlur={this.showData2} ref={this.myRef2} type="text" />
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
</script>
React中的事件处理
/*
通过onXxx属性指定事件处理函数
React使用的是自定义事件,而不是原生的DOM事件————为了更好的兼容性
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)————为了高效
通过event.target得到发生事件的DOM元素对象———— 不要过度使用ref
*/
React中的收集表单数据
- 非受控组件
<script type="text/babel"> // 此处一定要写babel
class Login extends React.Component {
handleSubmit = (e) => {
// 阻止表单的默认提交行为
e.preventDefault()
const { username, password } = e.target
alert(`用户名:${username.value} 密码:${password.value}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input type="text" name="username" />
密码:<input type="password" name="password" />
<button>登录</button>
</form>
)
}
}
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
- 受控组件
<script type="text/babel"> // 此处一定要写babel
class Login extends React.Component {
state = {
username: '',
password: ''
}
handleSubmit = (e) => {
// 阻止表单的默认提交行为
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username} 密码:${password}`)
}
//保存用户名到状态
saveUsername = (e) => {
// console.log(e.target.value);
this.setState({ username: e.target.value })
}
savePassword = (e) => {
this.setState({ password: e.target.value })
}
// 非受控组件:现用现取
// 受控组件:页面中所有输入类的DOM,随着输入把数据维护到状态中,需要用到的时候从状态中取出来
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username" />
密码:<input onChange={this.savePassword} type="password" name="password" />
<button>登录</button>
</form>
)
}
}
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
高阶函数_函数柯里化
- 简单例子
<script>
function sum(a) {
return (b) => {
return (c) => {
return a + b + c;
}
}
}
const res = sum(1)(2)(3)
console.log(res);
</script>
<script type="text/babel">
class Login extends React.Component {
state = {
username: '',
password: ''
}
handleSubmit = (e) => {
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username} 密码:${password}`)
}
/*
高阶函数:如果一个函数符合下面两个规范中的任何一个,那该函数就是高阶函数
1. 若A函数,接收的参数是一个函数,那么A就是高阶函数。
2. 若A函数,调用的返回值是一个函数,那么A就是高阶函数。
常见的高阶函数:Promise,setTimeout,arr.map()...........
函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
*/
saveFormData = (dataType) => {
//返回一个函数,这个函数就是onChange的回调函数
return (e) => {
// console.log(dataType, e.target.value);
this.setState({ [dataType]: e.target.value })
}
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveFormData('username')} type="text" name="username" />
密码:<input onChange={this.saveFormData('password')} type="password" name="password" />
<button>登录</button>
</form>
)
}
}
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
React中组件的生命周期
- 生命周期图(新)
- 生命周期图(旧)
<script type="text/babel">
class Life extends React.Component {
state = {
opacity: 1
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//这个函数是要被Life的实例对象调用的,与render函数同级别
//调用时机:组件挂载完毕
componentDidMount() {
this.timer = setInterval(() => {
let { opacity } = this.state
opacity -= 0.1
if (opacity <= 0) {
opacity = 1
}
this.setState({ opacity })
}, 200);
}
//组件将要被卸载时调用
componentWillUnmount(){
clearInterval(this.timer)
}
//render调用时机:1.初始化渲染 2.状态更新之后
render() {
return (
<div>
<h2 style={{ opacity: this.state.opacity }}>react学不会怎么办</h2>
<button onClick={this.death}>不活了</button>
</div>
)
}
}
ReactDOM.render(<Life />, document.getElementById('test'));
</script>
- react生命周期(旧)
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count构造器')
super(props)
this.state = {
count: 0
}
}
add = () => {
let { count } = this.state
this.setState({
count: count + 1
})
}
force = () => {
this.forceUpdate()
}
//组件将要挂载时
componentWillMount() {
console.log('Count will mount')
}
//组件挂载完毕
componentDidMount() {
console.log('Count did mount')
}
//将要卸载组件
death = () => {
console.log('Count will unmount');
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//控制组件更新的阀门
shouldComponentUpdate() {
console.log('Count shouldComponentUpdate');
return true
}
//组件将要更新
componentWillUpdate() {
console.log('Count will update');
}
//组件更新完毕
componentDidUpdate() {
console.log('Count did update');
}
render() {
console.log('Count render')
const { count } = this.state
return (
<div>
<h2>当前求和为{count}</h2>
<button onClick={this.add}>点我加1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>强制更新,不更改状态中的数据</button>
</div>
)
}
}
class A extends React.Component {
state = {
carName: '奔驰'
}
changeCar = () => {
this.setState({
carName: '宝马'
})
}
render() {
console.log('A render')
return (
<div>
<h2>我是A组件</h2>
<button onClick={this.changeCar}>换车</button>
<B carName={this.state.carName} />
</div>
)
}
}
class B extends React.Component {
//组件将要接收新的属性
componentWillReceiveProps(props) {
console.log('B will receive props', props);
}
shouldComponentUpdate() {
console.log('B shouldComponentUpdate');
return true
}
//组件将要更新
componentWillUpdate() {
console.log('B will update');
}
//组件更新完毕
componentDidUpdate() {
console.log('B did update');
}
render() {
console.log('B render')
return (
<div>
<h2>我是B组件,接收到的车是:{this.props.carName}</h2>
</div>
)
}
}
ReactDOM.render(<Count />, document.getElementById('test'))
</script>
- react生命周期(新)
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count构造器')
super(props)
this.state = {
count: 0
}
}
add = () => {
let { count } = this.state
this.setState({
count: count + 1
})
}
force = () => {
this.forceUpdate()
}
//用途:若state的值在任何时候都取决于props的值。不推荐使用
static getDerivedStateFromProps(props,state){
console.log('Count getDerivedStateFromProps',props,state)
return null
}
//在更新之前获取快照
//返回值将作为参数传递给componentDidUpdate
getSnapshotBeforeUpdate(){
console.log('Count getSnapshotBeforeUpdate');
return 1
}
//组件挂载完毕
componentDidMount() {
console.log('Count did mount')
}
//将要卸载组件
death = () => {
console.log('Count will unmount');
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//控制组件更新的阀门
shouldComponentUpdate() {
console.log('Count shouldComponentUpdate');
return true
}
//组件更新完毕
componentDidUpdate(preProps,preState,snapshotValue) {
console.log('Count did update',preProps,preState,snapshotValue);
}
render() {
console.log('Count render')
const { count } = this.state
return (
<div>
<h2>当前求和为{count}</h2>
<button onClick={this.add}>点我加1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>强制更新,不更改状态中的数据</button>
</div>
)
}
}
ReactDOM.render(<Count count={122}/>, document.getElementById('test'))
</script>
- getSnapshotBeforeUpdate使用
<script type="text/babel">
class NewsList extends React.Component {
state = {
newsArr: []
}
componentDidMount() {
setInterval(() => {
//获取原状态
const { newsArr } = this.state
//模拟一条新闻
const news = '新闻' + (newsArr.length + 1)
//更新状态
this.setState({
newsArr: [news, ...newsArr]
})
}, 1000);
}
getSnapshotBeforeUpdate(){
return this.refs.list.scrollHeight
}
componentDidUpdate(preProps,preState,snapshotValue){
this.refs.list.scrollTop += this.refs.list.scrollHeight - snapshotValue
}
render() {
return (
<div>
<div className="list" ref="list">
{
this.state.newsArr.map((n, index) => {
return <div key={index} className="news">{n}</div>
})
}
</div>
</div>
)
}
}
// 渲染虚拟DOM到页面
ReactDOM.render(<NewsList />, document.getElementById('test'))
</script>
React进阶
Create React App官网
css模块化
- css文件命名为
xxx.module.css - 在组件中引用样式文件:
import hello from './xxx.module.css' - 在组件中使用样式:
<div className={hello.样式类名}></div>
vscode插件
- ES7 React/Redux/GraphQL/React-Native snippets
- rcc和rfc分别创建类式组件和函数式组件
- imp 引入组件
- 其他快捷命令可查看插件文档
prop-types安装
npm i prop-types
js基础语法
let obj = {a:1,b:2}
delete obj.a
console.log(obj)
// confirm要写成window.confirm,否则不识别
removeTodo = (id)=>{
if(window.confirm('确定删除吗?')){
this.props.removeTodo(id)
}
}
脚手架配置代理
-
安装axios:
npm i axios -
Create React App官方文档:
https://create-react-app.dev/docs/proxying-api-requests-in-development/ -
React18使用 http-proxy-middleware代理跨域
npm install http-proxy-middleware --savesrc/setupProxy.js (配置好后一定重启项目)
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', createProxyMiddleware({ target: 'http://www.xxx.xxx', changeOrigin: true, pathRewrite: { '^/api': '' } }) ) }
兄弟组件间通信-消息订阅与发布
- 安装:
npm i pubsub-js --save - 使用:
- 引入:
import PubSub from 'pubsub-js' - 订阅:
PubSub.subscribe('事件名称',回调函数) - 发布消息:
PubSub.publish('事件名称',数据) - 要在组件的componentWillUnmount中取消订阅:
PubSub.unsubscribe('事件名称')
- 引入:
react-router-dom
- react-router分为三种:web、native、any 。其中web是专门给网页开发用的,native是专门给移动端开发的,any是通用的。
- 安装:
npm i react-router-dom - 基本使用
- 引入:
import { Link, Route, Routes } from 'react-router-dom' - 编写路由链接:
<Link className="list-group-item" to="/home">Home</Link> - 注册路由:
<Routes> <Route path='/about' element={<About />} /> <Route path='/home' element={<Home a={1}/>} /> </Routes> - 在index.js中引入BrowserRouter包裹App组件:
<BrowserRouter> <App /> </BrowserRouter>
- 引入:
- 路由组件与一般组件
- 一般组件:
<Home/> - 路由组件:
<Route path="/home" component={Home}/>(旧)<Route path="/home" element={<Home a={1}/>}>(新)
- 见
https://baimingxuan.github.io/react-router6-doc/components/nav-link - 封装组件 MyNavLink.jsx
App.jsximport React, { Component } from 'react' import { NavLink } from 'react-router-dom' export default class MyNavLink extends Component { render() { console.log(this.props); return ( <NavLink className={({ isActive }) => isActive ? "active" : ""} {...this.props} /> ) } }<!-- 下面标签中标签体内容'Home'会被作为props.children传给NavLink组件,children属性决定了标签体的内容。NavLink中使用{...this.props}会将所有传来的props都传给<NavLink>组件,其中就包括children属性 --> <MyNavLink to="/home">Home</MyNavLink>- V6 不再使用
<Switch>, 将所有的<Switch>元素升级为<Routes>,与 Switch 相比, Routes 的主要优势在于:
<Routes>中的所有<Route>和<Link>都是相对的。这导致在<Route path>和<Link to>中的代码更精简和更可预测。- 路由的选择基于最佳匹配,而不是按顺序遍历。这避免了由于在
<Switch>中定义较晚而导致无法到达的错误。 - 路由可以嵌套在一个地方,而不是分散在不同的组件中。
- 解决样式丢失问题
- 丢失原因:浏览器地址位于例如/hello/home路由路径下,刷新浏览器后,找不到
http://localhost:3000/hello/下有css样式文件,默认返回index.html页面 - 解决办法:
//方法一 <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.min.css"> //方法二 <link rel="stylesheet" href="/css/bootstrap.min.css"> //方法三,依然用 ./css开头,但是路由模式使用 HashRouter <link rel="stylesheet" href="./css/bootstrap.min.css"> <!-- index.js中 --> import React from 'react' import ReactDOM from 'react-dom/client' import { BrowserRouter,HashRouter } from 'react-router-dom' import App from './App' const root = ReactDOM.createRoot(document.getElementById('root')) root.render( <React.StrictMode> <HashRouter> <App /> </HashRouter> </React.StrictMode> ) - 一般组件: