1、js和jsx有什么区别,为什么要使用jsx
// ①jsx的使用
<script type="text/babel">
const VDOM = <h1 id='title'>hell,react</h1>
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
②js的使用
<script type="text/javascript">
const VDOM = React.createElement('h1', {id:'title'}, 'hello react')
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
使用js而不使用jsx的原因是:程序员写jsx会使代码更加简洁,而使用js来创建虚拟DOM,则会显得更加繁琐。虽然在jsx在执行bable转化的使用,仍然转化成js。
2、react虚拟dom和真实dom的区别?
<script type="text/babel">
const VDOM = <h1>hello,react</h1>
const TDOM = document.getElementById('test')
ReactDOM.render(VDOM, document.getElementById('test'))
console.log('虚拟DOM:',VDOM)
console.log('真实DOM:',TDOM)
debugger;
</script>
1、虚拟dom其实只是一个对象
2、虚拟dom比较“轻”, 真实dom比较"重",原因是react中的虚拟dom只是将抽离出一些可以用得到的属性,但是在真实dom中会加载全部属性。
3、虚拟dom存放在内存中,等到使用完成后,就会转化成真实dom,呈现在真实的页面上。
3、什么是XML,为什么会将XML换成json
<students>
<name>TOM</name>
<age>20</age>
</students>
缺点:数据保存少,需要消耗的空间多,所有才有了JOSN数据类型
4、JSX语法
1、定义虚拟dom的时候,不需要写引号
2、标签中混入js表达式时要使用{}
3、样式的类名指定不要使用class,而是使用className
4、内联样式,需要使用style={{color:value}}的形式去写
5、只有一个根标签
6、标签必须闭合
7、标签首字母
(1)若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
(2)若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错、
5、在jsx中使用的是js表达式,注意和js语句之间的区别
<script type="text/babel">
const data = ['vue','react', 'angular']
const VDOM = (
<ul>
{
// 使用大括号中间放的是js表达式,注意和js语句之间的区别
data.map((item,index)=> {
return <li key={index}>{item}</li>
})
}
</ul>
)
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
js表达式有:
1、a
2、a + b
3、arr.map()
4、function test()
5、函数调用 demo(1)
js语句有:
1、if语句
2、for循环语句
3、switch语句
5、函数式组件
1、基本实现
<script type="text/babel">
//创建函数式组件
function MyComponent () {
return <h2>这里是函数式组件</h2>
}
//执行render渲染操作
ReactDOM.render(<MyComponent/>, document.getElementById('test'))
</script>
执行函数式组件的步骤流程:
1、先找到MyComponent函数式组件
2、然后将返回的虚拟dom渲染成真实的dom
3、最后展示到页面上
6、类组件
<script type="text/babel">
class MyComponent extends React.Component {
render() {
console.log(this)
return <h1>这里是类组件的实现</h1>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('test'))
</script>
注意事项:
1、需要继承React.Component。
2、可以没有构造函数。
类式组件的执行流程
1、React解析先找到MyComponent组件
2、发现该组件是通过类进行定义的,首先通过new一个实例对象,然后调用实例对象中的render方法。
3、将render返回的虚拟dom转化成真是的dom,随后展示到页面上。
7、设置点击事件
1、ES6中的事件默认开启局部严格模式
2、 babel在进行转化js文件的时候,会避免this指向window,而是让this的值赋值给undefined。
<script type="text/babel">
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot : false
}
this.changeWeather = this.changeWeather.bind(this)
}
render() {
const {isHot} = this.state
return <h1 onClick={this.changeWeather}>今天天气真{isHot ? '炎热' : '寒冷'}</h1>
}
changeWeather() {
this.setState({
isHot:!this.state.isHot
})
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
//注意事项:
1、在调用函数的时候注意this的指向,可以使用bind
2、更改state中的值的时候,必须使用setState函数来进行更改,传入的参数是对象,是抽取更改不是全部覆盖。
3、在执行过程中,构造函数执行1次,render函数执行1 + n(n为修改的次数),changeWeather函数执行n次,n为点击的次数。
8、apply和call以及bind之间的区别?
1、bind方法
1、bind第一个参数为this指向的对象,第二个参数到第n个参数均为传入的值
2、bind的传入参数之后,需要再次进行调用
3、每次执行bind方法时都会新建一个函数
4、自己实现简单的bind方法
5、如果直接在bind后面只有一个括号,不能实现函数调用。
Function.prototype.my_bind = function (context) {
let self = this
return function () {
return self.apply(context, arguments)
}
}
function add (c, d) {
return this.x + c + d
}
console.log(add.bind({x:100}, 10, 1)())
二、call方法
1、第一个参数是this指向的对象,第二个参数到第n个参数是需要传入的值。
2、方法.call()可以实现函数调用。
三、apply方法
1、 第一个参数是this指向的对象,第二个参数是一个数组,也可以是arguments
2、方法.apply()也可以实现函数调用
9、触发事件的简写形式
<script type="text/babel">
class Weather extends React.Component {
state = { ----------------------------------①
isHot:true
}
render() {
const {isHot} = this.state
return <h1 onClick={this.changeWeather}>今天天气是{isHot ? '炎热' : '寒冷'}</h1>
}
changeWeather = () => { --------------------------②
this.setState({
isHot:!this.state.isHot
})
}
}
ReactDOM.render(<Weather />, document.getElementById('test'))
</script>
1、如果某一些属性不需要外部来传入,可以像①处这样写
2、可以将方法也不放在原型对象上,直接放在该类中,这里需要使用箭头函数,类似于图中的②
3、注意事件的书写格式上,需要将onclick写成onClick
11、类组件中的props属性
<script type="text/babel">
class Person extends React.Component {
render() {
const {name,age,sex} = this.props
console.log(this)
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="董礼" age="20" sex="男" />, document.getElementById('test'))
</script>
1、在每一个实例组件对象中都会存在一个属性props。
2、可以直接在组件进行传值
11、对象解构
<script>
let p1 = {name:'张三',age:20, sex:'男'}
let p2 = {...p1}
p1.name = '李四'
console.log(p1) //{name:'李四',age:20, sex:'男'}
console.log(p2) //{name:'张三',age:20, sex:'男'}
</script>
对象如果想要结构必须使用{...对象名},这样得到的就是另一个对象。
可以在给类组件传入参数时进行解构处理
原因:因为该文件是react和babel一起结合使用的,只能在组件标签中使用对象的解构。
<script type="text/babel">
class Person extends React.Component {
render () {
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
let p1 = {name:"张三", age:'20', sex: "男"}
ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
</script>
12、
设置传入props的数据类型以及是否被需要,并且可以设置props的属性默认值。
<script type="text/babel">
class Person extends React.Component {
render() {
const { name, age, sex ,speak} = this.props
console.log(speak)
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age + 1}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
// 设置类型
Person.propTypes = {
name:PropTypes.string.isRequired,
age:PropTypes.number.isRequired,
sex:PropTypes.string.isRequired,
speak:PropTypes.func,
}
// 设置默认值
Person.defaultProps = {
name:'董沐辰',
age:20,
sex:'女'
}
const p1 = {}
ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
ReactDOM.render(<Person name="李四" age={20} sex="男" speak = {speak}/>, document.getElementById('test1'))
function speak() {
console.log('我要说话')
}
1、这里还可以给函数类型限制,注意函数类型限制的类型必须是func,数字和字符串类型的限制必须使用小写。
2、如果需要给组件标签传入js代码,则必须使用{}来表示。
13、将该组件类中的属性设置为类的静态属性
<script type="text/babel">
class Person extends React.Component {
render() {
const {name,age,sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
static propTypes = {
name:PropTypes.string.isRequired,
sex:PropTypes.string,
age:PropTypes.number
}
static defaultProps = {
name:'张三',
}
}
let p1 = {name:'张三',age:20, sex:'男'}
ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
</script>
14、类中的构造器
//组件类的构造器的作用:
<script type="text/babel">
class Person extends React.Component {
constructor(props) {
super(props)
console.log('constructor', this.props)
}
render() {
const {name,age,sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
static propTypes = {
name:PropTypes.string.isRequired,
sex:PropTypes.string,
age:PropTypes.number
}
static defaultProps = {
name:'张三',
}
}
let p1 = {name:'张三',age:20, sex:'男'}
ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
</script>
官网上的constructor的两种用法:
1、通常,在react中,构造函数仅用于以下两种情况。
通过给this.state赋值对象类初始化内部的state。
为事件处理函数绑定实例。
第一个我们使用属性实现,第二个我们使用箭头函数实现
其实构造函数可以不进行使用,如果我们想要在构造函数中使用this.props,则必须传入props以及使用super(props)进行传值、
15、函数式组件
<script type="text/babel">
function Person(props) {
const {name, age, sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
Person.propTypes = {
name:PropTypes.string.isRequired,
age:PropTypes.number,
sex:PropTypes.string
}
Person.defaultProps = {
name:'李四',
age:300,
sex:'女'
}
ReactDOM.render(<Person/>, document.getElementById('test'))
</script>
在函数是组件中,需要注意的事项:
1、目前函数式组件没有this,但是只能得到props属性。
2、函数式组件中没有state和refs。
3、函数式组件可以通过给组件传属性,最终传入props中,并且可以给属性设置类型限制和设置默认值。
16、refs和ref的使用
<script type="text/babel">
class Demo extends React.Component {
set = () => {
const {input1} = this.refs
alert(input1.value)
}
bule= () => {
const {input2} = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击"/>
<button onClick={this.set}>点击我触发左侧事件</button>
<input ref="input2" onBlur={this.bule} type="text" placeholder="失去焦点"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script>
1、可以通过ref来获取该标签。
2、refs中包含了这个类组件对象中的全部的ref。
17、ref使用回调函数的形式,ref=字符串的形式效率太低。
<script type="text/babel">
class Person extends React.Component {
set = () => {
const {input1} = this
alert(input1.value)
}
blur = () => {
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={(currentNode)=> {this.input1 = currentNode}} type="text" placeholder='点击'/>
<button onClick={this.set}>点击</button>
<input ref={(currentNode) => {this.input2 = currentNode}} type="text" onBlur ={this.blur} placeholder='失去焦点'/>
</div>
)
}
}
ReactDOM.render(<Person/>, document.getElementById('test'))
</script>
1、如果ref=回调函数,比如使用{}把其括起来。
2、并且使用箭头函数的形式,因为箭头函数中的this指向的是这个实例对象本身。
3、ref传入的参数是该节点的对象,使用this.input = currentNode ,是向这个实例对象上面赋值.
4、最后在触发的方法中使用解构对this进行解构即可。
5、这里中的ref是react自动帮我们调用的函数。
18、ref设置内联函数和绑定函数的区别
1、内联函数
当页面发生改变的时候,页面会重新渲染,内联函数会执行两次,第一次传入的currentNode的值是null,第二次传入的是才是这个节点。
<script type="text/babel">
class Demo extends React.Component {
state = {
isHot:true
}
set = ()=> {
const {input1} = this
alert(input1.value)
}
changeWeather=() => {
this.setState({
isHot: !this.state.isHot
})
}
render () {
const {isHot} = this.state
return (
<div>
<h1>天气是{isHot ? '炎热' : '寒冷'}</h1>
<input type="text" ref={(currentNode)=> {this.input1 = currentNode;console.log('@@',currentNode)}}/>
<button onClick={this.set}>点击展示数据</button>
<button onClick={this.changeWeather}>点击修改天气</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script>
2、绑定函数 如果使用绑定函数的时候,当页面发生变化的时候,只会执行一次,并且传给currentNode的值,就是该节点。
<script type="text/babel">
class Demo extends React.Component {
state = {
isHot:true
}
set = ()=> {
const {input1} = this
alert(input1.value)
}
changeWeather=() => {
this.setState({
isHot: !this.state.isHot
})
}
sss = (currentNode) => {
this.input1 = currentNode
console.log('@@', currentNode)
}
render () {
const {isHot} = this.state
return (
<div>
<h1>天气是{isHot ? '炎热' : '寒冷'}</h1>
<input type="text" ref={this.sss}/>
<button onClick={this.set}>点击展示数据</button>
<button onClick={this.changeWeather}>点击修改天气</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script>
两者中第一个在开发中使用的频率高
第三种实现ref的方式
<script type="text/babel">
class Demo extends React.Component {
myRef = React.createRef()
myRef1 = React.createRef()
set = ()=> {
alert(this.myRef.current.value)
}
blur = () => {
alert(this.myRef1.current.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder='点击'/>
<button onClick={this.set}>点击</button>
<input onBlur={this.blur} ref={this.myRef1} type="text" placeholder='失去焦点'/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script>
1、这里使用React.createRef()这个API来进行创建。
2、在类对象实例上进行设置。
3、每一个React.createRef()只能使用一次。
19、react中的事件处理
1、注意事件的大小写,例如点击事件必须写成onClick
原因:因为需要考虑到事件的兼容性问题,并且和原来的事件区分开。
2、React中事件是通过事件委托的方式处理的(将事件委托给最外层的元素)使用的原理是事件冒泡。
为了高效
3、可以通过event.target得到发生事件的DOM元素的对象,原因是不能过度的使用ref。
<script type="text/babel">
class Demo extends React.Component {
blur = (event) =>{
console.log(event.target.value)
}
render() {
return (
<div>
<input onBlur= {this.blur} type="text"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script>
20、事件委托
1、事件委托利用的原理是事件冒泡。
2、事件委托减少操作dom的次数,可以极大解决性能的问题。
3、事件委托可以减少设置事件,减少内存占有。
21、非受控组件
<script type="text/babel">
class Form extends React.Component {
submitForm = (event) => {
event.preventDefault()
const {username, password} = this
alert(`提交的用户姓名为:${username.value},用户密码为:${password.value}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit ={this.submitForm}>
用户名:<input type="text" name="username" ref={c=> this.username = c}/>
密码:<input type="password" name="password" ref={c=> this.password = c}/>
<button>点击提交</button>
</form>
)
}
}
ReactDOM.render(<Form/>, document.getElementById('test'))
</script>
1、当在form表单中提交的时候,触发的事件是onSubmit事件。
2、event.preventDefault()表示阻止默认事件。
3、非受控组件就是什么时候需要用到ref表示的标签什么时候取出来即可。
22、受控组件
<script type="text/babel">
class Form extends React.Component {
state = {
username:'',
password: ''
}
nameChange = (event) => {
this.setState({
username:event.target.value
})
}
passChange = (event) => {
this.setState({
password:event.target.value
})
}
render() {
return (
<form action="">
姓名:<input type="text" onChange={this.nameChange}/>
密码:<input type="password" onChange={this.passChange}/>
</form>
)
}
}
ReactDOM.render(<Form/>, document.getElementById('test'))
</script>
受控组件和非受控组件的区别
1、受控组件,随时都能获取到组件中对应的值,类似于vue中的数据的双向绑定。
2、非受控组件,只有需要的时候才能获取到组件中对应的值,例如当提交表单时,才会获取表单中的对应的input框中的值。
3、而且我们在项目中最好使用受控组件。
对上面的受控组件进行化简
<script type="text/babel">
class Form extends React.Component {
state = {
username:'',
password:''
}
saveFormData = (data) => {
return (event) => {
this.setState({
[data]:event.target.value
})
}
}
render() {
return (
<form action="">
用户名:<input type="text" onChange = {this.saveFormData('username')}/>
密码:<input type="text" onChange = {this.saveFormData('password')}/>
</form>
)
}
}
ReactDOM.render(<Form/>, document.getElementById('test'))
</script>
设置saveFormData通过对其传入属性名,从而进行封装,避免代码冗余
23、高阶函数
定义:如果一个函数传入的参数是一个函数,或者返回的是一个函数,这两类满足其一,即可成该函数为高阶函数。
柯里化:
//代码如下所示即为柯里化,或者正如saveFormData这个函数就是柯里化
function set(a) {
return function (b) {
return function (c) {
return a + b + c
}
}
}
console.log(set(1)(2)(4))
在不使用柯里化和高阶函数的前提下,重写上述代码
<script type="text/babel">
class Form extends React.Component {
state = {
username: '',
password: ''
}
saveFormData(dataType, event) {
this.setState({
[dataType]:event.target.value
})
}
render() {
return (
<form action="">
用户名:<input type="text" onChange = {event=>this.saveFormData('username', event)}/> ----------------①
密码:<input type="text" onChange = {event =>this.saveFormData('password', event)}/> ----------------——②
</form>
)
}
}
ReactDOM.render(<Form />, document.getElementById('test'))
</script>
24、react生命周期
<script type="text/babel">
class Life extends React.Component {
state = {
opacity: 1
}
remove = () => {
// 卸载组件
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// 组件挂载完毕
componentDidMount() {
console.log('组件挂载完毕')
this.timer = setInterval(() => {
let {opacity} = this.state
opacity -= 0.1
this.setState({
opacity
})
if(opacity <= 0){ //这里不使用opacity == 0的原因是:因为js中小数相减存在误差
this.setState({
opacity:1
})
}
},200)
}
// 在卸载组件之前
componentWillUnmount() {
console.log('组件卸载之前')
clearInterval(this.timer)
}
render() {
console.log('render')
return (
<div>
<h1 style={{opacity:this.state.opacity}}>学不会React生命周期怎么办</h1> --------------------①
<button onClick={this.remove}>不活了</button>
</div>
)
}
}
ReactDOM.render(<Life/>, document.getElementById('test'))
</script>
1、ReactDOM.unmountComponentAtNode(document.getElementById('test'))表示卸载某一个组件。
2、componentDidMount表示组件挂在成功。
3、componentWillUnmount表示组件将要被写在之前。
4、组件中的render函数是在组件第一次渲染,以及后面的状态state中的值发生变化的时候,执行调用。
5、执行顺序是render -> componentDidMount -> componentWillUnmount
6、注意在掺入样式的时候需要使用双括号,正如①所示
出现错误:Can't perform a React state update on an unmounted component.
原因是无法在没有挂载的组件中修改state中的值。本例中是在清空之前关闭定时器。
<script type="text/babel">
class Count extends React.Component {
// 构造函数
constructor(props) {
console.log('现在执行constructor中的函数')
super(props)
}
state = {
count:1
}
changeCount = () => {
let {count} = this.state
this.setState({
count:++count
})
}
// 组件挂载之前
componentWillMount() {
console.log('现在执行componentWillMount中的函数')
}
// 组件挂载完成
componentDidMount() {
console.log('现在执行componentDidMount中的函数')
}
render() {
console.log('现在执行render中的函数')
return (
<div>
<h1>当前的数字是:{this.state.count}</h1>
<button onClick ={this.changeCount}>点击+1</button>
</div>
)
}
}
ReactDOM.render(<Count/>, document.getElementById('test'))
</script>
最终的结果是:
现在执行constructor中的函数
现在执行componentWillMount中的函数
现在执行render中的函数
现在执行componentDidMount中的函数
26、count++和++count,以及count = count++以及count = ++ count之间的区别
1、count++和++count都具有自增1的效果。
2、count=count++没有自增的效果。
3、count=++count有自增的效果。
29、setState()执行步骤
注意:当执行到shouldComponentUpdate的时候,需要返回一个Boolen值为true才能继续。
30、forceUpdate()进行强制更新状态
使用场景:当不需要更改状态,但是想要强制更新调用render可以通过forceUpdate进行。
<script type="text/babel">
class Father extends React.Component {
state = {
myCar : '保时捷'
}
changeCar = () => {
this.setState({
myCar:'奔驰C300'
})
}
render() {
return (
<div>
<h1>我有一辆车</h1>
<button onClick ={this.changeCar}>我要换车</button>
<Son myCar = {this.state.myCar}/>
</div>
)
}
}
class Son extends React.Component {
render() {
console.log('render')
return (
<div>
<h4>我是子组件</h4>
<h4>{this.props.myCar}</h4>
</div>
)
}
componentWillReceiveProps(props) {
console.log("componentWillReceiveProps")
console.log(props)
}
shouldComponentUpdate() {
console.log('shouldComponentUpdate')
return true
}
componentWillUpdate() {
console.log('componentWillUpdate')
}
componentDidUpdate() {
console.log("componentDidUpdate")
}
}
ReactDOM.render(<Father/>, document.getElementById('test'))
</script>
注意:componentWillReceiveProps第一次传入值的时候,不触发,第二次才进行触发
shouldComponentUpdate必须return true才能向下进行。
32、getDerivedStateFromProps
static getDerivedStateFromProps(nextProps,nextState){
if(nextProps.value!==undefined){
return {
current:nextProps.value
}
}
return null
}
简单来说,getDerivedStateFromProps的执行时机就是在组件初始化的时候以及组件后续更新的时候。同时getDerivedStateFromProps也可以最早的在父传子的时候获取到父组件传递给子组件的属性。由此可见,getDerivedStateFromProps很好的代替了componentWillMount以及componentWillReceiveProps。
33、getSnapshotBeforeUpdate
getSnapshotBeforeUpdate取代了componentWillUpdate
发时机为update发生的时候,在render之后、dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。
简答的应用场景:
//s比如列表更新后新的数据不断插入到数据前面,如何保证可视区依旧是之前看到的呢?(详细案例可以查看官网)
getSnapshotBeforeUpdate(){
return this.refs.wrapper.scrollHeight
}
componentDidUpdate(prevProps,prevState,preHeight){
this.refs.wrapper.scrollTop+=this.refs.wrapper.scrollHeight-preHeight
}
.....
35、diff算法
diff算法实现步骤:
1、首先获取状态更改的信息,将全部的状态数据转化成新的虚拟DOM
2、 将新的虚拟DOM和原来的虚拟DOM进行比对,根据key的值进行比对。
3、如果key相同,并且其中的内容也相同,则直接使用原来的虚拟DOM
4、如果key没有相同的,则直接将新的虚拟DOM渲染成真实DOM
5、如果key相同,并且其中也存在其他标签,也需要进行其他标签的比对,如果相同则继续使用。
6、diffing算法最低层次是标签。
7、diffing算法一般的key为id或者其他具有唯一性的值作为键。
36、React脚手架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- %PUBLIC_URL%作用就是指明图标所在文件是public文件 -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<!-- 进行移动端适配 -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 设置安卓中的搜索框中的颜色 -->
<meta name="theme-color" content="#000000" />
<!-- 设置搜索引擎的搜索关键字 -->
<meta
name="description"
content="Web site created using create-react-app"
/>
<!-- ios手机中添加某一个特定的网页添加到手机主屏幕后的图标 -->
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- 用于手机加壳 -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<!-- 当浏览器中不支持js的时候,才展示该标签 -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- 页面渲染的跟路径 -->
<div id="root"></div>
</body>
</html>
37、CSS模块化
出现的原因:
当不同组件中的Css样式中存在重名的情况,当最终引入到APP.js中只会导致后面组件的样式会将前面组件的样式覆盖掉。
解决方案:
给每一个css样式文件中间添加一个modules
并且引入的时候类似于引入js
看下方的代码:
import { Component } from "react";
import HelloCss from './Hello.module.css'
export default class Hello extends Component {
render() {
return (
<h1 className={HelloCss.Welcome}>hello组件</h1>
)
}
}
38、React中配置代理
第一种配置代理的方法:
在package.json中增添了一个属性proxy:http://localhost:5000
在package.json中追加的如下配置:
优点:配置简单,前端请求资源时可以不加任何前缀。
缺点:不能配置多个代理。
配置方法二:
在src下创建配置文件:src/setupProxy.js
编写setupProxy.js配置具体代理规则:
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.use(
proxy('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
changeOrigin默认值为false,但我们一般将changeOrigin值设为true
*/
pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
}),
proxy('/api2', {
target: 'http://localhost:5001',
changeOrigin: true,
pathRewrite: {'^/api2': ''}
})
)
}
说明:
1、优点:可以配置多个代理,可以灵活的控制请求是否走代理。
2、缺点:配置繁琐,前端请求资源时必须加前缀。