react(3)

打印 上一主题 下一主题

主题 1731|帖子 1731|积分 5193

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
七、react ajax

7.1明白

7.1.1前置阐明


  • React本身只关注于界面, 并不包含发送ajax哀求的代码
  • 前端应用需要通过ajax哀求与后台举行交互(json数据)
  • react应用中需要集成第三方ajax库(或自己封装)
7.1.2常用的ajax哀求库


  • jQuery: 比较重, 如果需要另外引入不建议使用
  • axios: 轻量级, 建议使用

    • 封装XmlHttpRequest对象的ajax
    • promise风格
    • 可以用在浏览器端和node服务器端

7.2脚手架配置代理

在终端分别打开server1.js,server2.js
(在演示时需要重新启动脚手架npm start)
方法一

在package.json中追加如下配置
  1. "proxy":"http://localhost:5000"
复制代码
阐明:

  • 长处:配置简单,前端哀求资源时可以不加任何前缀。
  • 缺点:不能配置多个代理。
  • 工作方式:上述方式配置代理,当哀求了3000不存在的资源时,那么该哀求会转发给5000 (优先匹配前端资源)
方法二


  • 第一步:创建代理配置文件
    1. 在src下创建配置文件:src/setupProxy.js
    复制代码
  • 编写setupProxy.js配置具体代理规则:
    1. const { createProxyMiddleware } = require('http-proxy-middleware')
    2. module.exports = function(app) {
    3.  app.use(
    4.    createProxyMiddleware('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
    5.      target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
    6.      changeOrigin: true, //控制服务器接收到的请求头中host字段的值
    7.      /*
    8.        changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
    9.        changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
    10.        changeOrigin默认值为false,但我们一般将changeOrigin值设为true
    11.      */
    12.      pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
    13.    }),
    14.    createProxyMiddleware('/api2', {
    15.      target: 'http://localhost:5001',
    16.      changeOrigin: true,
    17.      pathRewrite: {'^/api2': ''}
    18.    })
    19.   )
    20. }
    复制代码
阐明:

  • 长处:可以配置多个代理,可以灵活的控制哀求是否走代理。
  • 缺点:配置繁琐,前端哀求资源时必须加前缀。
7.3案例(含消息订阅)



描述:输入关键字,能够搜索出用户并展示(演示前打开服务器)
1.首先分析一下如何拆分组件,我们将这个案例分为List和Search组件,分别创建两个文件,并引入App.js,页面渲染用上组件标签
2.再分析一下网络哀求,我们希望建立一个代理服务器,当多次发送哀求时,Github可能禁止访问,这时我们可以在代理服务器上假造一些数据。
代理此时的端标语是5000,而我们所处的端标语为3000,以是我们采用方法二中的脚手架配置代理
参考上一部分内容即可
4.分析一下这两个组件的逻辑:
首先我们从Search组件中获得关键字,并发送哀求,拿到返回值。
然后将返回值传递给List组件,再渲染到页面上。此时我们可以通过消息订阅来完成兄弟组件的通讯。
消息订阅

a.首先全局安装消息订阅的包
  1. npm add pubsub-js
复制代码
b.再在需要使用的两个组件分别引入这两个包
  1. import PubSub from 'pubsub-js'
复制代码
c.在接收消息的组件中订阅消息
  1. this.token = PubSub.subscribe('消息名', (msg, data) => {
  2.            console.log(data)
  3.        })
复制代码
d.在发送消息的组件中发送消息
  1. PubSub.publish('消息名', data)
复制代码
e.取消消息订阅
  1. PubSub.unsubscribe(this.token)
复制代码

5.如今我们所需知识都已经把握,如今写Search组件
首先引入axios库,引入PubSub包,给按钮绑定点击变乱,利用ref打标识获取input元素的value值
在点击变乱中,首先获取关键字,发送哀求前关照List更新消息,发送axios哀求。
在axios哀求中:
a.域名是我们站在自己的端标语上,并且加上代理所需要的‘/api1’字段
b.利用promise语法,可获得返回数据。通过消息订阅将消息发布出去
  1. import React, { Component } from 'react'
  2. import axios from 'axios'
  3. import PubSub from 'pubsub-js'
  4. export default class Search extends Component {
  5.    search = () => {
  6.        // 连续解构赋值 + 重命名
  7.        const { keyword: { value: keyword } } = this
  8.        // 发送请求前通知List更新消息
  9.        PubSub.publish('xixi', { isFirst: false, isLoading: true })
  10.        // console.log(keyword)
  11.        axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then(
  12.            response => {
  13.                // console.log(response.data)
  14.                PubSub.publish('xixi', { isLoading: false, users: response.data.items })
  15.            }
  16.        )
  17.    }
  18.    render() {
  19.        return (
  20.            <div>
  21.                <section className="jumbotron">
  22.                    <h3 className="jumbotron-heading">搜索Github用户</h3>
  23.                    <div>
  24.                        <input ref={c => this.keyword = c} type="text" placeholder="输入关键字" />&nbsp;
  25.                        <button onClick={this.search}>Search</button>
  26.                    </div>
  27.                </section>
  28.            </div>
  29.        )
  30.    }
  31. }
复制代码
6.List组件
a.引入PubSub包
b.初始化state,在页面渲染时将state的数据渲染上去
c.在页面挂载完毕时,订阅消息,将state更新
d.在页面将要被卸载时,取消消息订阅
  1. import React, { Component } from 'react'
  2. import './index.css'
  3. import PubSub from 'pubsub-js'
  4. export default class List extends Component {
  5.    state = {
  6.        users: [],//
  7.        isFirst: true,//是否为第一次打开页面
  8.        isLoding: false,//标识是否处于加载之中
  9.        err: ''//存储请求相关的信息错误
  10.    }
  11.    componentDidMount() {
  12.        this.token = PubSub.subscribe('xixi', (msg, data) => {
  13.            // console.log(data)
  14.            this.setState(data)
  15.        })
  16.    }
  17.    componentWillUnmount() {
  18.        PubSub.unsubscribe(this.token)
  19.    }
  20.    render() {
  21.        const { users, isFirst, isLoding, err } = this.state
  22.        return (
  23.            <div>
  24.                <div className="row">
  25.                    {
  26.                        isFirst ? <h2>欢迎使用,输入关键字</h2> :
  27.                        isLoding ? <h2>Loading.....</h2> :
  28.                        err ? <h2>{err}</h2> :
  29.                        users.map((userObj) => {
  30.                        return (
  31.                               <div className="card" key={userObj.id}>
  32.                                <a href={userObj.html_url} target="_blank" rel="noreferrer">
  33.                                <img alt='头像' src={userObj.avatar_url} style={{ width: '100px' }} />
  34.                                </a>
  35.                                <p className="card-text">{userObj.login}</p>
  36.                               </div>
  37.                         )
  38.                         })
  39.                }
  40.                </div>
  41.            </div>
  42.        )
  43.    }
  44. }
复制代码
八、React路由

8.1相干明白

8.1.1SPA的明白


  • 单页Web应用(single page web application,SPA)。
  • 整个应用只有一个完整的页面
  • 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  • 数据都需要通过ajax哀求获取, 并在前端异步显现。
8.1.2路由的明白

1. 什么是路由?

  • 一个路由就是一个映射关系(key:value)
点击导航栏,它就改路径,改路径后被浏览器检测,检测到后就展示组件

  • key为路径, value可能是function或component
1. 路由分类

  • 后端路由:

    • 明白: value是function, 用来处理客户端提交的哀求。
    • 注册路由: router.get(path, function(req, res))
    • 工作过程:当node接收到一个哀求时, 根据哀求路径找到匹配的路由, 调用路由中的函数来处理哀求, 返反响应数据

  • 前端路由:

    • 浏览器端路由,value是component,用于展示页面内容。
    • 注册路由: <Route path="/test" component={Test}>
    • 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件

8.2react-router-dom相干API

全局安装react-router-dom
  1. npm add react-router-dom@5
复制代码
ps:对react-router-dom的明白:

  • react的一个插件库。
  • 专门用来实现一个SPA应用。
  • 基于react的项目根本都会用到此库。
8.2.1内置组件

  1. 1.  <BrowserRouter>
  2. 2.  <HashRouter>
  3. 3.  <Route>
  4. 4.  <Redirect>
  5. 5.  <Link>
  6. 6.  <NavLink>
  7. 7.  <Switch>
复制代码
8.2.2其他

  1. 1.  history对象
  2. 2.  match对象
  3. 3.  withRouter函数
复制代码
8.3路由的根本使用

8.3.1路由根本使用的案例

案例演示:通过点击旁边的导航栏,利用路由切换右侧展示区的内容


1.首先分析一下组件划分,标题和导航栏时公共用的,展示区由差异的组件表现,我们分为Home组件和About组件
2.在Home组件和About组件中简单写内容
3.主要是对App组件的编写:
引入react-router-dom库,引入两个所需组件。
Link是路由链接,通过编写路由链接来实现切换组件,to属性是修改路径
Route是注册路由,path属性是匹配对应的路径,component属性用来指定哪一个组件。
  1. // 创建外壳组件App
  2. import React, { Component } from "react"
  3. import { Link, Route } from 'react-router-dom'
  4. import Home from './components/Home'
  5. import About from "./components/About"
  6. export default class App extends Component {
  7.    render() {
  8.        return (
  9.            <div>
  10.                <div className="row">
  11.                    <div className="col-xs-offset-2 col-xs-8">
  12.                        <div className="page-header"><h2>React Router Demo</h2></div>
  13.                    </div>
  14.                </div>
  15.                <div className="row">
  16.                    <div className="col-xs-2 col-xs-offset-2">
  17.                        <div className="list-group">
  18.                            {/* <a className="list-group-item" href="./about.html">About</a>
  19.                            <a className="list-group-item active" href="./home.html">Home</a> */}
  20.                            <Link className="list-group-item" to="/about">About</Link>
  21.                            <Link className="list-group-item" to="/home">Home</Link>
  22.                        </div>
  23.                    </div>
  24.                    <div className="col-xs-6">
  25.                        <div className="panel">
  26.                            <div className="panel-body">
  27.                                <Route path="/about" component={About} />
  28.                                <Route path="/home" component={Home} />
  29.                            </div>
  30.                        </div>
  31.                    </div>
  32.                </div>
  33.            </div>
  34.        )
  35.    }
  36. }
复制代码
4.由于Link,Route标签都需要包裹在BrowserRouter标签里,并且只需要一个路由器举行管理,以是直接在index.js文件中将App标签包裹起来(记得引入react-router-dom库)
  1. // 引入
  2. import React from "react"
  3. import ReactDOM from "react-dom"
  4. import App from "./App"
  5. import { BrowserRouter } from "react-router-dom"
  6. // 渲染
  7. ReactDOM.render(
  8.    <BrowserRouter>
  9.        <App />
  10.    </BrowserRouter>,
  11.    document.querySelector('#root'))
复制代码
总结:路由器的根本使用
1.明确导航区和展示区
2.导航区的a标签改为Link标签
3.展示区写Route标签举行路径匹配
4.在App标签外侧包裹BrowserRouter标签
8.3.2路由组件与一般组件

1.写法差异:
  1. 一般组件:<Demo/>
  2. 路由组件:<Route path="/Demo" component={Demo} />
复制代码
2.存放地点差异:
  1. 一般组件:放在文件夹components
  2. 路由组件:放在文件夹pages
复制代码
3.接收到的props差异:
  1. 一般组件:传递的什么就能收到什么
  2. 路由组件:history,location,match接收到固定三个属性
复制代码
8.3.3NavLink

可以追加被点击后的高亮样式的类名
  1. <NavLink activeClassName="active" className="list-group-item" to="/about">About</NavLink>
  2. <NavLink activeClassName="active" className="list-group-item" to="/home">Home</NavLink>
复制代码
封装NavLink

由于NavLink写起来属性很多,大量编写时不方便,自己定义一个NavLink组件
1.首先在组件的文件夹里创建一个组件,取名MyNavLink。
在MyNavLink组件里,引入react-router-dom库,在返回值时,利用props传递参数
  1. import React, { Component } from 'react'
  2. import { NavLink } from 'react-router-dom'
  3. export default class MyNavLink extends Component {
  4.    render() {
  5.        return (
  6.            <NavLink activeClassName="active" className="list-group-item" {...this.props}></NavLink>
  7.        )
  8.    }
  9. }
复制代码
2.在原来使用NavLink的文件里(这里是App.js),使用MyNavLink组件
先引入MyNavLink组件,在导航区使用MyNavLink组件,并传递props值,这里需要注意的是,原来我们使用组件时,用的组件标签是子封闭,但是因为导航栏我们需要传递导航标题,以是我们利用下面这种情势。
  1. <MyNavLink to="/home">Home</MyNavLink>
  2. <MyNavLink to="/about">About</MyNavLink>
复制代码
标签体内容其实也是特别的props(可以打开控制台查看),属性名是children
8.3.4Switch

当路径匹配上一个之后,就展示组件,并不再向下举行匹配
备注:如果一个路径对应多个组件,不用Switch的情况下,React将多个组件一起展示,但是建议一个路径对应一个组件
使用方法如下:
1.引入
  1. import { Switch, Route } from 'react-router-dom'
复制代码
2.用Switch标签将注册路由包裹起来
  1. <Switch>
  2.     <Route path="/about" component={About} />
  3.     <Route path="/home" component={Home} />
  4. </Switch>
复制代码
总结:1.通常情况下,path和component是一一对应的关系
2.Switch可以提高路由匹配效率(单一匹配)
8.3.5Redirect重定向

1.一般写在全部路由注册的最下方,当全部路由都无法匹配时,跳转到Redirect指定的路由
2.具体编码
  1. <Redirect to="/指定的路径" />
复制代码
8.4嵌套路由

案例:在Home组件中还有路由组件


1.首先分析组件构成,大体框架与上一个案例相似,我们主要是改变Home组件的内容。
将Home组件的内容同样分为导航区和展示区,在展示区由News组价和Message组件构成。
以是在Home文件里创建两个子组件的文件夹,并将对应内容渲染在页面上
在Home/News/index.js中
  1. import React, { Component } from 'react'
  2. export default class News extends Component {
  3.    render() {
  4.        return (
  5.            <ul>
  6.                <li>news001</li>
  7.                <li>news002</li>
  8.                <li>news003</li>
  9.            </ul>
  10.        )
  11.    }
  12. }
复制代码
在Home/Message/index.js中
  1. import React, { Component } from 'react'
  2. export default class Message extends Component {
  3.    render() {
  4.        return (
  5.            <div>
  6.                <ul>
  7.                    <li>
  8.                        <a href="/message1">message001</a>&nbsp;&nbsp;
  9.                    </li>
  10.                    <li>
  11.                        <a href="/message2">message002</a>&nbsp;&nbsp;
  12.                    </li>
  13.                    <li>
  14.                        <a href="/message/3">message003</a>&nbsp;&nbsp;
  15.                    </li>
  16.                </ul>
  17.            </div>
  18.        )
  19.    }
  20. }
复制代码
2.在Home组件中,首先引入两个子组件,再引入自定义的MyNavLink组件,再引入react-router-dom库
在返回假造DOM时,编写路由链接,并注册路由
  1. import React, { Component } from 'react'
  2. import News from './News'
  3. import Message from './Message'
  4. import MyNavLink from '../../components/MyNavLink'
  5. import { Route, Switch, Redirect } from 'react-router-dom'
  6. export default class Home extends Component {
  7.    render() {
  8.        return (
  9.            <div>
  10.                <h2>Home组件内容</h2>
  11.                <div>
  12.                    <ul className="nav nav-tabs">
  13.                        <li>
  14.                            <MyNavLink to="/home/news">News</MyNavLink>
  15.                        </li>
  16.                        <li>
  17.                            <MyNavLink to="/home/message">Message</MyNavLink>
  18.                        </li>
  19.                    </ul>
  20.                    <Switch>
  21.                        <Route path="/home/news" component={News} />
  22.                        <Route path="/home/message" component={Message} />
  23.                        <Redirect to="/home/news" />
  24.                    </Switch>
  25.                </div>
  26.            </div>
  27.        )
  28.    }
  29. }
复制代码
注意:1.注册子路由时要写上父路由的path值,当React遇到Link标签时,是重新举行路径匹配,以是必须加上父路由的path值
2.路由的匹配是按照注册路由的顺序举行的
解决样式丢失题目

当多级路由后,用户强制刷新时,样式会丢失
解决方案:1.在public/index.html中引入样式时,不写 ./而是写 /
2.在public/index.html中引入样式时,不写 ./而是写%PUBLIC_URL%
3.不使用BrowserRouter标签包裹App标签,使用HashRouter
8.5向路由组件传递参数数据

案例结果:


8.5.1向路由组件传递params参数

1.首先分析组件构成,显然,在Message组件中,又分为导航区和展示区。由于展示区的大体结构雷同,以是我们就只写一个路由组件即可,别的信息通过传递参数来获取。
2.在Message文件夹中建立Details组件。
在Detials组件中,我们的消息内容是通过传递的参数来举行匹配的,以是我们先定义一个对象数组。然后返回假造DOM,这里结构先简单看一下。
  1. import React, { Component } from 'react'
  2. const details = [
  3.    { id: '01', content: '你' },
  4.    { id: '02', content: '好' },
  5.    { id: '03', content: '你好' },
  6. ]
  7. export default class Details extends Component {
  8.    render() {
  9.        console.log(this.props)
  10.        const { id, title } = this.props.match.params
  11.        const contents = details.find((detailObj) => {
  12.            return detailObj.id === id
  13.        })
  14.        return (
  15.            <ul>
  16.                <li>id:{id}</li>
  17.                <li>title:{title}</li>
  18.                <li>content:{contents.content}</li>
  19.            </ul>
  20.        )
  21.    }
  22. }
复制代码
3.在Message组件中,我们先引入Details组件,引入react-router-dom库
我们先初始化state,创建一个数组。然后在render函数里,首先解构赋值messageArr,用遍历数组的方式渲染导航栏的部分。
在导航栏,我们用Link路由链接编写:由于要传递参数,要用模板字符串。
在展示区,我们用Route注册路由,通过/:的语法传递参数。
  1. import React, { Component } from 'react'
  2. import Details from './Details'
  3. import { Route, Link } from 'react-router-dom'
  4. export default class Message extends Component {
  5.    state = {
  6.        messageArr: [
  7.            { id: '01', title: '消息1' },
  8.            { id: '02', title: '消息2' },
  9.            { id: '03', title: '消息3' }
  10.        ]
  11.    }
  12.    render() {
  13.        const { messageArr } = this.state
  14.        return (
  15.            <div>
  16.                <ul>
  17.                    {
  18.                        messageArr.map((msgObj) => {
  19.                            return (
  20.                                <li key={msgObj.id}>
  21.                                    {/* 向路由传递params参数 */}
  22.                                    <Link to={`/home/message/details/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
  23.                                </li>
  24.                            )
  25.                        })
  26.                    }
  27.                </ul>
  28.                <hr />
  29.                {/* 声明接收params参数 */}
  30.                <Route path="/home/message/details/:id/:title" component={Details} />
  31.            </div>
  32.        )
  33.    }
  34. }
复制代码
4.路由链接里的参数传递到那里了?
打印Details组件的props我们发现,props.match.params里


以是我们返回Details组件,将接收到的id,title举行解构赋值,并通过find方法匹配出内容,渲染在页面上。
总结:
1.路由链接(携带参数):
  1. <Link to={`/home/message/details/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
复制代码
2.注册路由(声明接收):
  1. <Route path="/home/message/details/:id/:title" component={Details} />
复制代码
3.子路由组件接收参数:
  1. const { id, title } = this.props.match.params
复制代码
8.5.2向路由组件传递search参数

大体结构雷同,只是在上面总结的三步有差异
总结:
1.路由链接(携带参数):
  1. <Link to={`/home/message/details/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
复制代码
2.注册路由(声明接收):
  1. <Route path="/home/message/details" component={Details} />
复制代码
3.子路由组件接收参数:(引入qs库)
  1. 在引入的部分:import qs from 'qs'
  2. 在render函数里:
  3.         const { search } = this.props.location
  4.        const { id, title } = qs.parse(search.slice(1))
复制代码
备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
8.5.3向路由组件传递state参数

总结:
1.路由链接(携带参数):
  1. <Link to={{ pathname: '/home/message/details', id: msgObj.id, title: msgObj.title }}>{msgObj.title}</Link>
复制代码
2.注册路由(声明接收):
  1. <Route path="/home/message/details" component={Details} />
复制代码
3.子路由组件接收参数:(引入qs库)
  1. const { id, title } = this.props.location
  2. const contents = details.find((detailObj) => {
  3.            return detailObj.id === id
  4. }) || {}
复制代码
备注:如果强制刷新,state会酿成undefined,contents这个部分会报错,以是加上||{},如果是undefined,则赋值为空对象
8.6push与replace

一般默认push模式,是以压栈的情势,但是当你开启replace模式后,是更换栈顶。
开启replace模式:
  1. <Link replace={true} to={{ pathname: '/home/message/details', id: msgObj.id, title: msgObj.title }}>{msgObj.title}</Link>
复制代码
8.7编程式路由导航

不通过Link大概NavLink标签,使用路由跳转。我们利用this.props.history里的push和replace方法
案例:给按钮绑定变乱,可以通过点击按钮选择查看消息的方式。
这个时候不能用Link标签写死了,以是我们给按钮绑定变乱,在回调函数里调用this.props.history里的push和replace方法。其他步调不改变。
  1. 回调函数:
  2. pushShow = (id, title) => {
  3.        this.props.history.push(`/home/message/details/${id}/${title}`)
  4.    }
  5.    replaceShow = (id, title) => {
  6.        this.props.history.replace(`/home/message/details/${id}/${title}`)
  7.    }
  8. 绑定事件:
  9. <button onClick={() => { this.pushShow(msgObj.id, msgObj.title) }}>push</button>
  10. <button onClick={() => { this.replaceShow(msgObj.id, msgObj.title) }}>replace</button>
复制代码
此案例用的params传递参数的情势,其他传递参数的方式可以自己实验一下
补充:this.props.history.goBack() 回退
this.props.history.goForward() 前进
this.props.history.go(num) 前进或退却num页
8.8withRouter

withRouter可以加工一般组件,让一般组件具有路由组件所特有的API
withRouter的返回值是一个新的组件
使用方法:
  1. import { withRouter } from 'react-router-dom'
  2. export default withRouter(Headers)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美丽的神话

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表