day19

一、setState进阶

1.setState是一个异步函数

在执行this.setState时,后续的代码会马上执行

state = {
   num:100
}
numChange(){
   var num = this.state.num;
   this.setState({
       num:++num
  });
   console.log(this.state.num)//此时获取到的数据不是最新的
}
render() {
   return (
       <div>
           <h1>index组件</h1>
           <h2>num:{ this.state.num }</h2>
           <button onClick={ ()=>this.numChange() }>增加</button>
       </div>
  )
}

解决办法:

setState可以接收第二个参数,这个参数就是回调函数

回调函数,就是在执行完某个操作后,自动调用的函数

this.setState({ num:++num },()=>{
console.log(this.state.num)
});

2.state和props混用

state 状态机,定义组件初始数据

props 接收父组件传递过来的数据

父子组件上都有挂载完成钩子函数,在函数都通过setState来修改数据,由于子组件挂载完成后父组件才算挂载完成,会产生一个数据不一致的问题。

解决方法:

setState的第一个参数使用函数,这个函数中可以接收两个参数

第一个参数是组件自己的数据,第二个参数父组件传递过来的最新数据

总结:

setState 作用:会把指定数据与原有的数据进行合并,并重新渲染页面

如果要在执行setState后获取到最新的数据时,需要使用第二个参数(回调函数)

如果组件中把state和props混用时,建议在setState中使用函数

 

示例代码:

父组件:

import React, { Component } from 'react'
import Child from './Child'
export default class Index extends Component {
   state = {
       num:100
  }
   componentDidMount(){
       // console.log('父组件挂载完成...')
       this.setState({
           num:200
      })
  }
   numChange(){
       var num = this.state.num;
       this.setState({ num:++num },()=>{
           console.log(this.state.num)//在回调函数中可以获取到最新的数据
      });
       // console.log(this.state.num)//这里获取到的数据不是最新的
  }
   render() {
       return (
           <div>
               <h1>index组件</h1>
               <h2>num:{ this.state.num }</h2>
               <button onClick={ ()=>this.numChange() }>增加</button>
               <hr/>
               <Child indexnum={ this.state.num }></Child>
           </div>
      )
  }
}

子组件:

import React, { Component } from 'react'
export default class Child extends Component {
   state = { num:50 }
   componentDidMount(){
       // console.log('子组件挂载完成...')
       // this.setState({
       //     num:this.props.indexnum
       // })
       // setState如果第一个参数是函数的话
       // 第一个参数是组件自己的数据,第二个参数父组件传递过来的最新数据
       this.setState(function(state,props){
           state.num = props.indexnum;
      })
  }
   render() {
       return (
           <div>
               <h2>child组件</h2>
               <h2>num:{ this.state.num }</h2>
           </div>
      )
  }
}

二、DOM操作-ref

1.字符串

<h2 ref="myh2">num:{ this.state.num }</h2>

在组件挂载完成的钩子函数中对它进行操作

componentDidMount(){
  this.refs.myh2.innerHTML = 'hello ref'
}

refs在react中已被弃用

2.回调函数

<Child ref={(ev)=>this.setChild(ev)}></Child>

在自定义方法中对子组件进行数据的修改

setChild(el){
   //el 现在就是子组件本身
   if(el){
       el.setState({
           num:300
      })
  }
}

3.createRef

在构造函数中使用React.createRef方法,在React推荐使用这种方式,因为回调函数的方式会自动的触发。

constructor(){
  super();
  this.childEl = React.createRef();
}

在子组件上添加ref属性

<Child ref={ this.childEl }></Child>

在父组件的挂载完成钩子函数中,就可以直接修改的数据或者调用子组件的方法

componentDidMount(){
   this.childEl.current.setState({
       num:200
  })
}

三、代理配置和网络请求

1.代理配置

(1)改变React默认运行端口

①在启动react项目时,选择更换端口

②修改文件

node_moudles/react-scripts/scripts/state.js第64行

const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 5000;

③package.json中设置端口

"scripts": {
  "start": "set PORT=3333 && react-scripts start",
  ...

(2)设置代理转发规则

package.json中设置

"proxy":"http://localhost:3000"

==proxy==是一个一级配置选项

(3)通过插件http-proxy-middleware实现代理转发设置

在package.json中进行设置代理规则,只要不是路由规则的请求地址都会进行代理转发,所以为了更加准确的给指定的请求进行代理转发,需要使用插件来实现。

先把package.json中的proxy选项删除

①安装插件

npm i http-proxy-middleware --save

②在src目录下,创建一个文件,文件名叫:setupProxy.js,并配置转发规则

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

③重启项目

2.fetch

fetch('/api/getcate').then(response=>response.json()).then(res=>{
console.log(res)
})

3.axios

npm i axios
import axios from 'axios'

axios.get('/api/getcate').then(res=>{...})

四、路由

1.安装

npm i react-router-dom --save

2.引入

src/index.js 引入路由模式组件

BrowserRouter是history模式

HashRouter是hash模式

import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.render(<BrowserRouter><App/></BrowserRouter>,document.getElementById("root"));

3.基本使用

(1)先创建几个页面组件

(2)在src/App.js根组件中引入路由出口和路由规则组件,并定义路由规则

import { Switch,Route } from 'react-router-dom'
import Index from './components/pages/Index'
import Login from './components/pages/Login'
function App() {
   return (
       <div className="App">
           <Switch>
               <Route path="/index" component={ Index }></Route>
               <Route path="/login" component={ Login }></Route>
           </Switch>
       </div>
  );
}
export default App;

Switch是路由出口,作用和vue中router-view相同

Route是具体的一个路由规则,需要设置path属性和component属性

4.重定向

import { Switch,Route,Redirect } from 'react-router-dom'


<Switch>
<Route path="/index" component={ Index }></Route>
  <Route path="/login" component={ Login }></Route>
<Redirect path="*" to="/index"></Redirect>
</Switch>

5.路由导航

(1)内置组件

Link、NavLink

他们两个都会在页面上生成a标签,都需要设置to属性

NavLink会根据当前访问的路由规则给指定的组件设置激活状态的类名

示例代码:

引入需要的组件

import { Switch,Route,Redirect,Link,NavLink } from 'react-router-dom'

使用

<Link to="/index">首页</Link>
<Link to="/login">登录页</Link>
<hr/>
<NavLink to="/index">首页</NavLink>
<NavLink to="/login">登录页</NavLink>

(2)编程式导航

只要使用了路由,由路由渲染出来的页面组件的props中包含了路由相关属性和方法

this.props.history.push

this.props.history.replace

this.props.history.go(-1)

this.props.history.goBack()

6.路由嵌套

如果某个页面需要展示出来不同的子级页面,那么就在这个页面中继续引入Switch和Route,定义 好路由出口和路由规则,就可以不子级页面内容展示路由出口的位置。

posted @ 2021-01-30 10:39  安亦辰00  阅读(273)  评论(0)    收藏  举报