资讯详情

react学习日记

react

react-hello world

第一个react程序hello world

<body>     <div id="test"></div><!--表示视图  -->     <script src="./js/react.development.js"></script>     <script src="./js/react-dom.development.js"></script>     <script src="./js/babel.min.js"></script>     <script type="text/babel">         //创建虚拟DOM         let vDom=<h1>hello world</h1>         //建虚拟DOM渲染到视图层         ReactDOM.render(vDom,document.getElementById("test"))     </script> </body>

虚拟DOM创建方式

react虚拟DOM有两种创作方式:

第一:创建单级虚拟:DOM

let vDom=<h1>hello world</h1>

二是创建有子节点的虚拟DOM

let vDom=(     <h1 id="title">         <span>你好!世界</span>     </h1> )

认识虚拟DOM

虚拟打印在控制台上DOM

可见虚拟DOM是个一般的object对象的属性会比真实的更真实DOM多,因为虚拟DOM被react所用,不需要太多属性,虚拟DOM最后也会被渲染成真实DOM。

在{}内部使用{}包裹需要注释的代码js注释

let vDom=(     <div>         <h1 id="title">             {/*<span>你好!世界</span>*/}         </h1>         <div id='div1'></div>     </div> )

JSX语法糖

let vDom=(     <div>         <h1 id="title">             <span>你好!世界</span>         </h1>         <div id='div1'></div>     </div> )

<script type="text/babel">         //创建虚拟DOM         let vID='title'         let vDom=(             <div>                 <h1 id={vID}>                     <span>你好!世界</span>                 </h1>                 <div id='div1'></div>             </div>         )         //建虚拟DOM渲染到视图层         ReactDOM.render(vDom,document.getElementById("test"))     </script>

虚拟DOM添加class属性名需要使用className

    <style>         .div1{             height: 100px;             width: 100px;             background-color: red;         }     </style>     <script type="text/babel">         //创建虚拟DOM         let vID='title'         let vDom=(             <div>                 <h1 id={vID}>                     <span>你好!世界</span>                 </h1>                 <div id='div1' className="div1"></div>             </div>         )         //建虚拟DOM渲染到视图层         ReactDOM.render(vDom,document.getElementById("test"))         console.log(vDom)     </script>

<div style={     
      { backgroundColor:'blue',height:100 'px', width:200 'px'}}></div>

react面向组件编程

组件编程:将页面分成功能模块,每个功能模块表示组件。每个组件都有自己的html(虚拟DOM),css以及js代码。(包括页面部分功能的所有代码和资源集合,即组件)

函数组件:适用于简单组件

函数组件,定义函数,首字母大写,返回虚拟DOM,通过render函数通过组件将其函数渲染到页面上。

注:函数组件this指向的是underfined,因为react开启严格模式。

<script type="text/babel"> let vID = 'title' function Compon() {//函数组件,必须是首字母大写     return (         <div>             <h1 id={vID}>                 <span>你好!世界</span>             </h1>             <div id='div1' className="div1"></div>             <div style={     
      { backgroundColor: 'blue', height: 100   'px', width: 200   'px' }}></div>     </div>     ) }             //渲染组件标签,必须有结束符号 ReactDOM.render(<Compon />, document.getElementById("test")) </script>

注:函数组件不能使用:state和refs,但是可以用props

使用函数组件props

提示:先看类组件props这里有相关知识

函数组件的属性将以参数的形式传输到函数组件的内部,相关约束不能在组件内部定义,只能在外部定义

<script type="text/babel">     function Person(props) {         let {name,age}= props         return (<h1>{name} {age}</h1>)         }     Person.propTypes = {         name: PropTypes.string.isRequired,         age: PropTypes.number,         }     Person.defaultProps = {         name: 'XXX'     } ReactDOM.render(<Person name='xiaozhi' age={12}/>, document.getElementById("test"))
</script>

类组件:适用于复杂组件

需要继承React.Component类

<style>
    .div1 {
        height: 100px;
        width: 100px;
        background-color: red;
    }
</style>
<script type="text/babel">
let vID = 'title'
class MyComponent extends React.Component {
    render() {
        return (
          <div>
            <h1 id={vID}>
                <span>你好!世界</span>
            </h1>
            <div id='div1' className="div1"></div>
            <div style={
    
      { backgroundColor: 'blue', height: 100 + 'px', width: 200 + 'px' }}></div>
        </div>
        )
        }
}
ReactDOM.render(<MyComponent />, document.getElementById("test"))
console.log(vDom)
</script>

类组件中的this指向类的实例对象

state:类组件实例的状态管理器,用于存放类中的状态(变量)

在构造器中,通过this.state设置类组件的状态,状态默认是null,在老版本的react默认是一个空对象。

<script type="text/babel">
    //创建虚拟DOM
    let vID = 'title'
    class MyComponent extends React.Component {
        constructor(props){
            super(props)
            this.state={gender:0}
        }
    render() {
        //读取状态
        let {gender}=this.state
        return (
            <h1 id={vID}>
                <span>你好!你的性别是{gender==0?'女':'男'}</span>
            </h1>
            )
    }
}
ReactDOM.render(<MyComponent />, document.getElementById("test"))
</script>

react将原始的JavaScript事件进行一层封装,其名称为小驼峰命名法与原生的JavaScript进行区别

例如onclick封装成onClick

class MyComponent extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
				gender: 0
			}
		this.changeGender = this.changeGender.bind(this)
		}
	changeGender() {
		console.log("aa",this);
		}
	render() {
		return (
			<h1 id={vID} onClick={this.changeGender()}>//会自启动一次
			    <span>你好!你的性别是{this.state.gender == 0 ? '女' : '男'}</span>
			</h1>
			)
		}
}

以上代码的方法有两个问题:

问题一:方法会在页面启动的时候执行一次,原因是在{...}内的代码相当于JavaScript代码,this.changeGender()表示的是调用该函数。

需要改成:

<h1 id={vID} onClick={this.changeGender}>

问题二:函数changeGender的this指向underfined,原因是因为在类组件中定义方法,在方法内部开启了严格模式,所以会指向underf

解决:初始化时,通过bind将this指向类组件的实例

constructor(props) {
    super(props)
    this.changeGender = this.changeGender.bind(this)
}

react是不允许直接修改state,而是需要使用setState来修改状态

class MyComponent extends React.Component {
    constructor(props) {
        super(props)
        this.state = {gender: 0}
        this.changeGender = this.changeGender.bind(this)
        }
        changeGender() {
            this.setState({gender: !this.state.gender})
        }
        render() {
            return (
                <h1 id={vID} onClick={this.changeGender}>
                    <span>你好!你的性别是{this.state.gender == 0 ? '女' : '男'}</span>
                </h1>
            )
        }
}

注意:setState不会覆盖state而是通过合并的方式修改state,如果没有该值,将会添加到state但是无法响应到页面。

state可以写在类的构造函数外面,自定义的方法通过箭头函数的方式可以实现this查找

class MyComponent extends React.Component {
	state = {gender: 0}//提取出来
	changeGender=()=> {//使用箭头函数,可先外出查找到this
		this.setState({gender: !this.state.gender})
	}
	render() {
		return (
			<h1 id={vID} onClick={this.changeGender}>
				<span>你好!你的性别是{this.state.gender == 0 ? '女' : '男'}</span>
				<span>{this.state.genders}</span>
			</h1>
			)
		}
}

props表示的是组件属性的实例对象

ReactDOM.render(<MyComponent name='xiaozhi' age='18'/>,
 document.getElementById("test"))

例如以上代码,其props的值则为:

{
    "name": "xiaozhi",
    "age": "18"
}

我们可以在组件中,通过this.props来获取其属性和属性值

<script type="text/babel">
    //创建虚拟DOM
    let vID = 'title'
    class MyComponent extends React.Component {
        state = { gender: 0 }
        render() {
            let name=this.props.name    
            return (
                <h1 id={vID} >
                    <span>{name}</span>
                </h1>
                )
            }
    }
ReactDOM.render(<MyComponent name='xiaozhi' age={18} />, document.getElementById("test"))
</script>

我们也可以通过批量进行传值

<script type="text/babel">
    //创建虚拟DOM
    let vID = 'title'
    class MyComponent extends React.Component {
        state = { gender: 0 }
        render() {
        let name=this.props.name    
        return (
            <h1 id={vID} >
                <span>{name}</span>
            </h1>
            )
        }
}
let p={name:'小智',age:18}
ReactDOM.render(<MyComponent {...p} />, document.getElementById("test"))
</script>

在组件实例上有个属性propsType可以对其进行类型限制以及必要性约束(需要引props-type包)

<script type="text/babel">
	//创建虚拟DOM
	let vID = 'title'
	class MyComponent extends React.Component {
		state = { gender: 0 }
		render() {
			let name = this.props.name
			return (
				<h1 id={vID} >
					<span>{name}</span>
				</h1>
				)
	}
}
	MyComponent.propTypes = {
		name: PropTypes.string.isRequired,//name的数据类型是string,必传
		age: PropTypes.number,//age的数据类型为number,可不传
		fn: PropTypes.funcage的数据类型为函数,可不传
	}
	let p = { name: '13', age: 18 }
	ReactDOM.render(<MyComponent {...p} fn={fn} />, document.getElementById("test"))
	function fn() {
		console.log('111');
	}
</script>

同理,在组件实例上有个属性defaultProps可以设置props的默认值

<script type="text/babel">
	class MyComponent extends React.Component {
		state = { gender: 0 }
		render() {
			let {name, sex} = this.props
			return (
				<h1>
					<span>{name}--{sex}</span>
				</h1>
			)
		}
	}
MyComponent.defaultProps={
		sex:'男'
	}
let p = { name: '13', age: 18 }
ReactDOM.render(<MyComponent {...p} fn={fn} />, document.getElementById("test"))
</script>

给类添加一个静态属性即可:static

class MyComponent extends React.Component {
	state = { gender: 0 }
	static propTypes = {
		name: PropTypes.string.isRequired,
		age: PropTypes.number,
		fn: PropTypes.func
	}
	static defaultProps = {
		sex: '男'
	}
	render() {
		let { name, sex } = this.props
		return (
			<h1 id={vID} >
				<span>{name}--{sex}</span>
			</h1>
		)
	}
}

注意:props是不允许被修改的

constructor(props){
	super(props)
    console.log(this.props)//如果不传,这里将会报undefined
}

官网说明

React.Component – React

在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug。

通常,在 React 中,构造函数仅用于以下两种情况:

  • 通过给 this.state 赋值对象来初始化[内部 state。

  • 为事件处理函数]绑定实例

    constructor(props) {
    	super(props)
        //初始化[内部 state
    	this.state = {gender: 0}
        //事件处理函数]绑定实例
    	this.changeGender = this.changeGender.bind(this)
    }

constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state` 赋值初始 state

避免将 props 的值复制给 state!这是一个常见的错误.

refs表示标签的唯一属性,用于获取元素节点实例,refs属性挂载在组件实例上。

class MyComponent extends React.Component {
	getInput = () => {
		let { input1 } = this.refs
		console.log(input1.value)
	}
	getInput2 = () => {
		let { input2 } = this.refs
		console.log(input2.value)
	}
	render() {
		return (
			<div>
				<input ref='input1' type="text" placeholder="输入" />
				<input type="button" onClick={this.getInput} value="请输入" />
				<input type="text" ref='input2' onBlur={this.getInput2} placeholder="点击输入" />
			</div>
		)
	}
}

注意:使用字符串形式的ref会有效率问题,不建议大量使用。

class MyComponent extends React.Component {
    getInput = () => {
        let { input1 } = this
        console.log(input1.value)
    }
    getInput2 = () => {
        let { input2 } = this
        console.log(input2.value)
    }
    render() {
        return (
            <div>
                <input ref={(a)=>{this.input1=a}} type="text" placeholder="输入" />
                <input type="button" onClick={this.getInput} value="请输入" />
                <input type="text" ref={(c=>this.input2=c)} onBlur={this.getInput2} placeholder="点击输入" />
            </div>
        )
    }
}

解析:

<input ref={(a)=>{this.input1=a}} type="text" placeholder="输入" />

ref={(a)=>{this.input1=a}}这段代码中,参数a表示的是节点的实例对象,this.input1=a表示的是将节点的实例对象挂载到组件实例上,名字取为input1。获取不在使用refs获取而是直接通过取的昵称获取到实例。

注意:关于调用次数问题,回调函数在初始化的时候会执行一次,当组件更新的时候,将执行两次。

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

react提供createRef来创建一个用于存储ref实例的一个容器,创建的容器只能存储一个ref实例,如果需要多个refshilling,则需要创建多个容器。使用current可以获取其实例

class MyComponent extends React.Component {
    inputRef = React.createRef();
    inputRef2 = React.createRef();
    getInput = () => {
        console.log(this.inputRef)
    }
    getInput2 = () => {
        let { input2 } = this
        console.log(this.inputRef2.current)
    }
    render() {
        return (
            <div>
                <input ref={this.inputRef} type="text" placeholder="输入" />
                <input type="button" onClick={this.getInput} value="请输入" />
                <input type="text" ref={this.inputRef2} onBlur={this.getInput2} />
            </div>
        )
    }
}

注意:低版本不支持该API

受控组件和非受控组件

受控组件:输入类型的标签,收集其值得时候,会随着值得变化而进行收集(类似vue的自动收集变量)

非受控组件:输入类型的标签,只有在使用数据的时候才会收集。

react事件处理

react的事件封装了原生的JavaScript事件(为了兼容),react事件使用了事件委托的方式绑定了事件,会将事件绑定到最外层的元素,可以通过target获取到操作的属性实例对象。

函数柯里化

class MyComponent extends React.Component {
    state = {
        name: '',
        pass: ''
    }
    submit = () => {
        console.log("@", this.state);
    }
    getData(types) {
        return (event) => {
            this.setState({ [types]: event.target.value })
            console.log(this.state);
        }
    }
    render() {
        return (
            <form>
                <input type="text" onChange={this.getData('name')} placeholder="用户名" /><br />
                <input type="password" onChange={this.getData('pass')} placeholder="密码" /><br />
                <input type="button" value="提交" onClick={this.submit} />
            </form>
        )
    }
}

如以上代码,在无法实现同时接收多个参数的时候,可以使用高接函数-柯里化函数。

function fn(a){
    return(b)=>{
        return(c)=>{
            return a+b+c
            }
        }
}
console.log(fn(1)(2)(3));

这种方式就是函数柯里化

class MyComponent extends React.Component {
	state = {
		name: '',
		pass: ''
	}
	submit = () => {
		console.log("@", this.state);
	}
	getData(types,event) {
			this.setState({ [types]: event.target.value })
			console.log(this.state);	
	}
render() {
	return (
	<form>
	  <input type="text" onChange={(event)=>{this.getData('name', event)}} placeholder="用户名"/><br/>
	  <input type="password" onChange={(event)=>this.getData('pass', event)} placeholder="密码"/<br/>
	  <input type="button" value="提交" onClick={this.submit} />
	</form>
		)
	}
}

这种方式就是在内联定义一个函数,在函数内调用组件内的方法。

react生命周期

react的生命周期主要有两个方面:组件挂载卸载,组件更新(父组件调render函数,调用serState函数,调用forceUpdate函数)。

组件挂载和卸载

constructor():构造器

componentWillMount():组件即将挂载

render():初始化调用一次,用于初始化数据

componentDidMount():组件已挂载

componentWillUnmount():组件即将卸载

componentDidUnmount():卸载组件(编程人员也可主动卸载)

执行顺序自上而下

render()函数在使用定时器的时候,不要进行状态修改,因为状态修改之后,会有调用render函数,这会导致进入递归死循环。

卸载组件的时候,一定要及时清理定时器,一般在componentWillUnmount()函数内清理

组件更新:

this.setState()

shouldComponentUpdate():控制组件是否进行更新,默认放回ture,放回false的时候,往后相关的生命周期函数将不执行

componentWillUpdate():组件即将更新

render():更新

componentDidUpdate():组件更新完毕

this.forceUpdata()

表示强制更新,一般使用场景是在不更新状态的情况下,进行页面更新。

componentWillUpdate():组件即将更新

render():更新

componentDidUpdate():组件更新完毕

父组件调用render()

  • componentWillReceiveProps:表示接收父组件传入的props属性时调用,参数为props,注意:第一次转入不算,只有从第二次props发生改变时才会调用。

  • shouldComponentUpdate

  • componentWillUpdate

  • render

  • componentDidUpdate

这个是v16.3版本以前的声明周期函数,v16.3对react的声明周期函数进行了更新和弃用,并在v17版本正式启用。

17版本新的声明周期函数

componentWillMount,componentWillUpdate,componentWillReceiveProps三个生命周期函数改名了,如果需要使用这三个声明周期,需要加前缀UNSAFE_

原因官网给出的介绍为:

这些生命周期方法经常被误解和滥用;此外,我们预计,在异步渲染中,它们潜在的误用问题可能更大。我们将在即将发布的版本中为这些生命周期添加 “UNSAFE_” 前缀。(这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,尤其是在启用异步渲染之后。)

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

static getDerivedStateFromProps(props, state){
    return {
        name: props.name,
        age:props.age
    }
}

此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。

派生状态会导致代码冗余,并使组件难以维护。即没啥大的意义!

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

应返回 snapshot 的值(任意非null值都是快照值)(或 null)。

常用的三个声明周期钩子函数:

render,componentDidUpdate,componentWillUnmount。

react脚手架

全局安装脚手架

npm install -g create-react-app

创建脚手架

npx create-react-app my-app cd my-app npm start

如果发现无法安装,是因为以前可能全局安装了低版本的create-react-app,卸载掉即可

或者忽略全局的脚手架:执行

npx --ignore-existing create-react-app my-app

还有问题,请移步该博客

安装create-react-app失败遇到的问题_宽粉儿~的博客-CSDN博客_react安装失败

使用脚手架创建第一个react组件

创建一个文件夹component用于存放组件,style文件夹用于存放样式。

在MyComponent.jsx文件写代码

import React from 'react'
//import '../style/index.css' 这种方式也可以
import style from '../style/index.css' //样式模块化,用的不多,一般都是用上面那种
class MyComponent extends React.Component { 
    render() { 
        return (
            <h1 className='style.title'>这是脚手架第一个组价</h1>
        )
    }
}
export { MyComponent}

index.css样式代码

.title{
    color: red;
}

在App.js引入组件并渲染

import {MyComponent} from './component/MyComponent'
function App() {
  return (
    <div className="App">
      <MyComponent />
    </div>
  );
}
export default App;

组件间通信

父子组件通信

使用props进行通信,请移步至props知识点

兄弟组件通信

父组件

class App extends React.Component {
  state = {
    itemList: ["吃饭", "喝酒", "看电视"]
  }
  addItem = (item) => {
    let newState = this.state.itemList.push(item)
    this.setState({
      itemList: newState
    })
  }
  render() {
    return (
      <div className="App">
        {/* 先子组件传方法间接修改数据 */}
        <Add addItem={this.addItem} />
         {/* 兄弟组件二:用于展示数据 */}
        <List {...this.state} />
      </div>
    )
  }
}

Add组件

class Add extends React.Component {
    add = (event) => {
        if (event.keyCode === 13) {
        this.props.addItem(event.target.value)
        }
    }
    render() { 
        return (
            <div>
                <input type="text" placeholder='请输入内容' onKeyDown={ (event)=>this.add(event)}/>
            </div>
        )
    }
}

通过执行父组件的方法,间接父组件的数据,从而实现兄弟组件之间的数据通信。

使用pubsub插件库

npm i pubsub-js

发布消息:用于传递数据

PubSub.publish('MY TOPIC', 'hello world!');

订阅消息:用于接收数据

var mySubscriber = function (msg, data) {
    console.log( msg, data );
};
var token = PubSub.subscribe('MY TOPIC', mySubscriber);

取消订阅发布

PubSub.unsubscribe(token);

方式和兄弟之间通信类似,在父组件上定义一个 修改父组件数据的方法,传给子组件,子组件调用该方法,传入相关的参数即可实现子父之间的数据传输。

网络请求

使用axios发送请求并封装axios

博主使用的技术栈是vue,之前自己封装过,就不浪费时间进行封装了,请移步axios官网:

axios中文网|axios API 中文文档 | axios

import axios from 'axios'

componentDidMount() { 
        axios.get('https://mock.apipost.cn/app/mock/project/fee3d514-9c37-4f69-9be0-ea185d142d90/getname').then(res => { 
            console.log(res);
        }).catch(error => { 
            console.log(error);
        })
    }

这是我用apiPost写的一个mock接口,模拟请求,想要实现可以到官网上下载apiPost

fetch

fetch是一个内置的请求,只要promise过关,不难,所以就不对说了

Fetch API - Web API 接口参考 | MDN

react配置代理

{
  "proxy":"http://localhost:3000"
}

这种方式只能配置一个代理

const proxy = require('http-proxy-middleware')
module.exports = function (app) {
  app.use(
    proxy('/api', {
      target: 'http://localhost:3000',
      changeOrigin: true,
      pathRewrite: {
        '^/api': '',
      },
    })
  )
}

该方式可以配置多个代理。

react-router-dom

该库是专门为web设计的路由库,使用的版本是V5版本,和V6版本有所不同。

组件

<BrowserRouter>:使用history模式,刷新页面会请求相关资源,会导致props丢失问题。
<HashRouter>:使用hash模式,刷新页面不会发请求
<Link>:路由入口
<NavLink>:<Link>组件的升级版,自带高亮效果,可设置activeClassName属性指定样式类名实现高亮效果
<Prompt>
<MemoryRouter>:
<Redirect>:重定向
<Route>:路由出口
<Router>
<StaticRouter>
<Switch>:注册路由(V5),用于路由一一匹配
<Routes>:注册路由(V6),替换用于<Switch>,这是新版本的内容<Route path="/A" element={<A/>}></Route>

组件封装:以封装NavLink为例

定义组件:MyComponent.jsx

import {Component } from 'react'
import { NavLink } from 'react-router-dom'
export default class List extends Component {
    render() { 
        console.log(this.props);
        return (
            <div className='my-link'>
                <NavLink {...this.props}>{ this.props.children}</NavLink>
            </div>
        )
        
    }
}

使用组件

import MyComponent from './component/MyComponent'
<MyComponent to="/A" a="100">关于</MyComponent>

注意:可以使用this.props.children获取组件的标签体。

Switch组件的使用

<Route path="/A" component={A}></Route>
<Route path="/B" component={B }></Route>
<Route path="/B" component={C }></Route>

老版本这样是,进入/B路由都会渲染B和A路由组件,但是路由是需要一一对应的,所以可以使用 Switch对其进行注册,实现一一对应。

        <Switch>
          <Route path="/A" component={A}></Route>
          <Route path="/B" component={B }></Route>
          <Route path="/B" component={C }></Route>
        </Switch>

使用Switch就可保证在进入/B路由的时候,只会渲染B组件。

关于使用BrowserRouter方式导致请求出错的问题

在index.html中引入样式

<link rel="stylesheet" href="./style.css">

在组件中,使用相关样式规则

<NavLink to="/A" activeClassName="active">进入A </Link>
<NavLink to="/B" activeClassName="active"> 进入B</Link>

当页面启动时,请求的样式资源路径为:

http://localhost:3000/style.css

此时,我们在路径新的访问接口为

<NavLink to="/A/A" activeClassName="active">进入A </Link>
<NavLink to="/B/B" activeClassName="active"> 进入B</Link>
<Route path="/A/A" component={A}></Route>
<Route path="/B/B" component={B }></Route>

第一次请求的资源路径为:

http://localhost:3000/style.css

刷新页面后的请求资源路径为:

http://localhost:3000/A/style.css

这就导致样式未加载到,

引入资源使用相对路径

<link rel="stylesheet" href="./style.css">
 改为
<link rel="stylesheet" href="/style.css">
 或者
 <link rel="stylesheet" href="style.css">
 或者
<link rel="stylesheet" href="%PUBLIC_URL%/style.css">

路由匹配

<NavLink to="/A/B/C" activeClassName="active">进入A </Link>
<Route path="/A" component={A}></Route>

react路由匹配默认开启模糊匹配,在进入路径一般会匹配路由路径,如果没有将会匹配到含有该路径的路由,即匹配到

开启精准匹配

<Route exact={true} path="/A" component={A}></Route>

精准匹配尽量别开启,因为在二级路由的时候,容易导致匹配不到。

Redirect

<Switch>
  <Route path="/A" component={A}></Route>
  <Route path="/B" component={B}></Route>
  <Redirect to="/B"></Redirect>
</Switch>

表示匹配不到时将会进B这个组件

路由嵌套

只需在该路由下再写入一个路由即可

如,我们为A路由嵌套一个路由

render() {
    return (
      <div className="App">
        <Link to="/A">进入A </Link>
        <Link to="/B"> 进入B</Link>
      <Switch>
         <Route path="/A" component={A}></Route>
          <Route path="/B" component={B}></Route>
      </Switch>
      </div>
    )
  }

在A路由组件写入代码:

render() { 
        return (
            <div>
                <Link to='/A/C'>点我</Link>
                <Switch>
                    <Route path="/A/C" component={ C}></Route>
                </Switch>
            </div>
        )
    }

这样即可实现路由的嵌套。

路由传参

params参数

class A extends React.Component {
    state = {msg: [{id: 1,name:'小智'},{id: 2,name:'小红'}]}
render() { 
    let { msg}=this.state
    return (
        <div>{
                msg.map((item, index) => {
                return (<Link key={index} to={`/A/C/${item.id}/${item.name}`}>{ item.name}</Link>)
               })
            }
            <Switch>
                <Route path="/A/C/:id/:name" component={ C}></Route>
            </Switch>
        </div>
    )}}

在入口Link将参数拼接到路由地址上,在出口Route使用占位符来表示参数,在该路由路径所对应的组件的props属性就可以获取到路由参数

return (
    <div>
        {this.props.match.params.id}+{ this.props.match.params.name}
    </div>
)

search参数

该方式就是向路由地址拼接参数

return (
    <div>
    {
        msg.map((item, index) => {
            return (
                <Link key={index} to={`/A/C?id=${item.id}&name=${item.name}`}>{ item.name}</Link>)
            })}
        <Switch>
                <Route path="/A/C" component={ C}></Route>
        </Switch>
    </div>
)

在props的localtoin有个属性叫search的就携带了该参数

: "?id=1&name=小智"

我们先需要将?截取掉在将其转为对象,react提供了一个库叫qs(有的版本叫querystring),可以将其转成对象

import qs from 'qs'
    class C extends React.Component {   
        render() { 
            let querys = qs.parse(this.props.location.search.slice(1))
    return (
        <div>
            {querys.id}+{ querys.name}
        </div>
    )
    }
}

state参数

不同于组件的state属性。

class A extends React.Component {
    state = {
        msg: [{id: 1,name:'小智'},{id: 2,name:'小红'}]
    }
render() { 
    let { msg}=this.state
    return (
        <div>
            {
            msg.map((item, index) => {
                return (
                    <Link key={index} to={
    
      { pathname: '/A/C', state: {id:item.id,name:item.name}}}>{ item.name}</Link>
                )
            })
            }
            <Switch>
                <Route path="/A/C" component={ C}></Route>
            </Switch>
        </div>
    )
}
}

传参形式

<Link key={index} to={
    
      { pathname: '/A/C', state: {id:item.id,name:item.name}}}>{ item.name}</Link>

在相对应的路由

class C extends React.Component {   
    render() { 
        let querys = this.props.location.state
        console.log(this.props.location);
    return (
        <div>
            {querys.id}+{ querys.name}
        </div>
    )}}

这个方式参数不会在地址栏显示,刷新参数也不会丢失。

参数模式

一共有两种模式,push和replace,默认push模式,即有浏览记录,replace表示的是通过路由地址替换,无法实现路由的前进和后退功能。

开启replace模式

<Link replace key={index} to={
    
      { pathname: '/A/C', state: {id:item.id,name:item.name}}}></Link>

编程式路由导航

this.props.history提供了两种路由跳转方式:push(path,state)和replace(path,state)

class C extends React.Component {
    state = {
        person: {name: 'xiaozhi',age:18}
    }
    gotoD = (p) => { this.props.history.push("/D",p)}
render() { 
    return (
        <div>
            <input type="button" value="进入D页面" onClick={()=>this.gotoD(this.state.person)}/>
        </div>
    )
    }
}

这种方式传的参数是state,其他方式只有一个参数,即参数拼接在url上。注意,路由D一定要注册,我这注册的地址为:

<Route path="/D" component={D}></Route>

在App.jsx文件注册的。

标签: d142对射式光电传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台