React system study notes - super basic - super detailed - super concise - React Ajax (4)

This part requires a preparatory technology stack: ajax, Axios

1 Configure proxy in React ( proxy)

The cross-domain request is sent, but the response is intercepted

The essence of cross-domain generation is that the browser ajax engine intercepts the response, and the proxy server (middleman) does not have an ajax engine; the proxy server forwards the request

Method 1 简单代理: package.jsonAdd the following configuration in :"proxy":http://localhost:5000

PS: Look for it when sending get http://localhost:3000, if you write 5000 again, it will still cause cross-domain. With the above proxy configured, not all requests are forwarded to 5000, but when you request, you use it to http://localhost:3000make a request. When it 3000cannot find resources in the port, it will automatically forward to 5000the port to make the request, without cross-domain problems (first in 3000 search, if not found, forward to 5000)

Advantages: simple configuration, no prefix can be added when the front end requests resources

Cons: Cannot configure multiple proxies

Working method: Configure the proxy in the above way. When a resource that does not exist in 3000 is requested, the request will be forwarded to 5000 (matching front-end resources first)

Method 2: Create a configuration file under src:src/setupProxy.js

PS: It must be this file name. When the react project is running, it will automatically find this file and add it to the configuration of webpack, so when you modify this file, you need to restart the project

Advantages: Multiple proxies can be configured, and it is possible to flexibly control whether requests go through proxies

Disadvantages: The configuration is cumbersome, and the front end must add a prefix when requesting resources

//代码示例CJS
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,欺骗一下服务器是从5000发的而不是3000发的
       	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
       	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
       */
       pathRewrite: {
    
    '^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
     }),
     proxy('/api2', {
    
     
       target: 'http://localhost:5001',
       changeOrigin: true,
       pathRewrite: {
    
    '^/api2': ''}
     })
   )
}

2 GitHub search case

insert image description here

ES6 tips: 连续赋值解构 + Rename

let obj = {
    
    a:{
    
    b:1}}
const {
    
    a} = obj; //传统解构赋值
const {
    
    a:{
    
    b}} = obj; //连续解构赋值
const {
    
    a:{
    
    b:value}} = obj; //连续解构赋值+重命名
console.log(value)

Note: The setupProxy.js file in the new React should be written like this:

//不是const proxy = require('http-proxy-middleware')
const {
    
     createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function (app) {
    
    
    app.use(
        createProxyMiddleware('/api1', {
    
    
            target: 'http://localhost:5000',
            changeOrigin: true,
            pathRewrite: {
    
     '^/api1': '' }
        })
    )
}

Search obtains data, and List needs data, but they are brothers, so search first gives data to App (this requires App to give search a function in the past), and then App gives data to List

App.js

export default class App extends Component {
    
    

  //初始化状态
  state = {
    
     users: [] }

  //状态在哪,操作状态的方法就在哪
  saveUsers = (users) => {
    
    
    this.setState({
    
     users: users })
  }
  render() {
    
    
    return (
      <div className="container">
        {
    
    /* 父给子提前传个函数 saveUsers*/}
        <Search saveUsers={
    
    this.saveUsers} />
        {
    
    /* 自己拿着没用,转手交给儿子 */}
        <List users={
    
    this.state.users} />
      </div>
    )
  }
}

Search.js

export default class Search extends Component {
    
    

    search = () => {
    
    
        //获取用户的输入
        //连续解构赋值写法+重命名
        const {
    
     keyWordNode: {
    
     value: keyWord } } = this
        //发送网络请求
        axios.get(`http://localhost:3000/api1/search/users?q=${
      
      keyWord}`).then(
            response => {
    
    
                this.props.saveUsers(response.data.items)
            },
            error => {
    
     console.log('成功了', error); }
        )
    }
    render() {
    
    
        return (
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索Github用户</h3>
                <div>
                    <input ref={
    
    c => {
    
     this.keyWordNode = c }} type="text" placeholder="输入关键词点击搜索" />&nbsp;					  <button onClick={
    
    this.search} >搜索</button>
                </div>
            </section>
        )
    }
}

List.js

export default class List extends Component {
    
    
    render() {
    
    
        return (
            <div className="row">
                {
    
    
                    this.props.users.map((userObj) => {
    
    
                        return (
                            <div className="card" key={
    
    userObj.id}>
                                <a href={
    
    userObj.html_url} target="_blank" rel="noreferrer">
                                    <img alt='head_portrait' src={
    
    userObj.avatar_url} style={
    
    {
    
     width: '100px' }} />
                                </a>
                                <p className="card-text">{
    
    userObj.login}</p>
                            </div>
                        )
                    })
                }
            </div>
        )
    }
}

In addition to displaying Users, List also displays: welcome page, loading page, error message (state-driven page display, so prepare in advance)

The complete version of the code display:

//App.js
export default class App extends Component {
    
    

  //初始化状态
  state = {
    
    
    //初始化数组
    users: [],
    //是否第一次打开页面
    isFirst: true,
    //是否加载中,发送请求前调为true
    isLoading: false,
    //错误休息
    err: ''
  }

  //状态在哪,操作状态的方法就在哪,更新App的state
  updateAppState = (stateObj) => {
    
    
    this.setState(stateObj)
  }
  render() {
    
    
    return (
      <div className="container">
        <Search updateAppState={
    
    this.updateAppState} />
        <List {
    
    ...this.state} />
      </div>
    )
  }
}

//Search.js
search = () => {
    
    
    //获取用户的输入
    //连续解构赋值写法+重命名
    const {
    
     keyWordNode: {
    
     value: keyWord } } = this
    //发请求前通知App更新状态
    this.props.updateAppState({
    
     isFirst: false, isLoading: true })
    //发送网络请求
    axios.get(`http://localhost:3000/api1/search/users?q=${
      
      keyWord}`).then(
        response => {
    
    
            //请求成功后通知App更新状态
            this.props.updateAppState({
    
     isLoading: false, users: response.data.items })
        },
        error => {
    
    
            //请求失败后通知App更新状态
            this.props.updateAppState({
    
     isLoading: false, err: error.message })
        }
    )
}

//List.js注意写表达式!
export default class List extends Component {
    
    
    render() {
    
    
        const {
    
     isFirst, isLoading, err } = this.props
        return (
            <div className="row">
                {
    
    
                    isFirst ? <h2 className='welcome'>欢迎进入鱼仔的GitHub搜索小案例,请输入关键字点击搜索</h2> :
                        isLoading ? <h2 className='loading'>鱼仔拼命地帮您加载中!!!请稍后!!!</h2> :
                            err ? <h2 className='error'>{
    
    err}</h2> :
                                this.props.users.map((userObj) => {
    
    
                                    return (
                                        <div className="card" key={
    
    userObj.id}>
                                            <a href={
    
    userObj.html_url} target="_blank" rel="noreferrer">
                                                <img alt='head_portrait' src={
    
    userObj.avatar_url} style={
    
    {
    
     width: 											  '100px' }} />
                                            </a>
                                            <p className="card-text">{
    
    userObj.login}</p>
                                        </div>
                                    )
                                })
                }
            </div >
        )
    }
}

3 Message Subscription and Publishing Mechanism

Suitable for communication between arbitrary components

Tool library used: PubSubJS

Install:npm i pubsub-js

Message subscription and release version of GitHub search case

//App.js
export default class App extends Component {
    
    
  render() {
    
    
    return (
      <div className="container">
        <Search />
        <List />
      </div>
    )
  }
}
//Search组件发布消息,把数据带给List
search = () => {
    
    
    //获取用户的输入
    //连续解构赋值写法+重命名
    const {
    
     keyWordNode: {
    
     value: keyWord } } = this
    //发请求前通知List更新状态
    PubSub.publish('getData', {
    
     isFirst: false, isLoading: true })
    //发送网络请求
    axios.get(`http://localhost:3000/api1/search/users?q=${
      
      keyWord}`).then(
        response => {
    
    
            //请求成功后通知List更新状态
            PubSub.publish('getData', {
    
     isLoading: false, users: response.data.items })
        },
        error => {
    
    
            //请求失败后通知List更新状态
            PubSub.publish('getData', {
    
     isLoading: false, err: error.message })
        }
    )
}
//List订阅消息,收到数据
//初始化状态--放在List中
state = {
    
    
    //初始化数组
    users: [],
    //是否第一次打开页面
    isFirst: true,
    //是否加载中,发送请求前调为true
    isLoading: false,
    //错误休息
    err: ''
}

componentDidMount() {
    
    
    this.token = PubSub.subscribe('getData', (msg, stateObj) => {
    
    
        this.setState(stateObj)
    })
}

componentWillUnmount() {
    
    
    PubSub.unsubscribe(this.token)
}
//注意这两处不是在propd中取了,是在state
const {
    
     isFirst, isLoading, err } = this.state
this.state.users.map

4 fetchsend request

Review Ajax

xhr: the most primitive, no encapsulation (built-in)

jQuery: encapsulated api, may cause callback hell (encapsulation of xhr)

axios: no callback hell (encapsulation of xhr)

fetch: 关注分离the design idea (that is, not to give you the data at once), the browser's native AJAX interface,老版本浏览器可能不支持

Fetch sends a request: (successful contact with the server and the server's response to non-response data are two things)

  • The first step is to contact the server first, and then get the data. At this time, the data has not been taken out (you can directly disconnect the browser to contact the server and fail), and establish a connection.
  • In the second step, the prototype object of response has the json() function, and response.json() returns a Promise instance . The data you want to get is on this Promise instance object. If you succeed in contacting the server and obtaining the data, then this The state of the promise is successful and the data you want is saved. If the contact with the server succeeds but fails to obtain the data, then the promise is in the state of failure, and the reason for the failure to save in it

Knowledge: the first .then will only return one of success or failure, and the return value of .then success or failure is a non-promise value, then the status of the promise instance returned by .then is successful, and the value is the non-promise value; if The return value of success or failure is a promise value, then it is used as the value of the promise instance returned by .then

The summary is that if used directly fetch, what is returned is not a direct result, it is just one HTTP响应, not real data

There are two ways to get data:

  • Use the chain call of promise, return it in the first then, and use it in the next then
  • Use async+await to get

Code example:

----------------------------- 未优化:使用then链式调用 ---------------------------------------------------------
fetch(`/api1/search/users2?q=${
      
      keyWord}`).then(
			response => {
    
    
				console.log('联系服务器成功了');
				return response.json()
			},
			error => {
    
    
				console.log('联系服务器失败了',error);
				return new Promise(()=>{
    
    })//返回一个初始化的实例就不会往下走了
			}
		).then(
			response => {
    
    console.log('获取数据成功了',response);},
			error => {
    
    console.log('获取数据失败了',error);}
) 

----------------------------- 第一次优化:最后统一处理错误 ------------------------------------------------------
fetch(`/api1/search/users2?q=${
      
      keyWord}`).then(
    response => {
    
    
        console.log('联系服务器成功了');
        return response.json()
    },
).then(
    response => {
    
     console.log('获取数据成功了', response); },
).catch(
    error => {
    
     console.log('获取数据失败了', error); }
)
----------------------------- 再优化后:使用async+await ---------------------------------------------------------
try {
    
    
		const response= await fetch(`/api1/search/users2?q=${
      
      keyWord}`)
		const data = await response.json()
		console.log(data);
		} catch (error) {
    
    
		onsole.log('请求出错',error);
		}
}

Guess you like

Origin blog.csdn.net/m0_55644132/article/details/127774075