日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

react好租客项目Day11-发布房源模块(js输入框防抖图片上传)项目打包项目优化(按需加载路由代码分割)

發布時間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 react好租客项目Day11-发布房源模块(js输入框防抖图片上传)项目打包项目优化(按需加载路由代码分割) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

房源發布模塊

目標

  • 如何解決JS 文本輸入框防抖(用戶輸入過快導致請求服務器的壓力過大)
  • 能夠完成搜索模塊
  • 能夠獲取發布房源的相關信息
  • 能夠知道圖片上傳的流程
  • 能夠完成圖片上傳功能
  • 能夠完成房源發布功能

前期準備工作

功能

  • 獲取房源的小區信息,房源圖片上傳,房源發布等

模板改動說明

  • 修改首頁(Index)去出租鏈接為: /rent/add
  • 修改公共組件NoHouse的children屬性校驗為: node(任何可以渲染的內容)

  • 修改公共組件HousePackage,添加onSelect的默認值

  • 添加utils/city.js,封裝當前定位城市 localStorage的操作

  • 創建了三個頁面組件:Rent(已發布房源列表)、Rent/Add(發布房源)、Rent/Search(關鍵詞搜索校區信息)

  • Rent 模板代碼
import React, { Component } from 'react'import { Link } from 'react-router-dom'import { API, BASE_URL } from '../../utils'import NavHeader from '../../components/NavHeader' import HouseItem from '../../components/HouseItem' import NoHouse from '../../components/NoHouse'import styles from './index.module.css'export default class Rent extends Component {state = {// 出租房屋列表list: []}// 獲取已發布房源的列表數據async getHouseList() {const res = await API.get('/user/houses')const { status, body } = res.dataif (status === 200) {this.setState({list: body})} else {const { history, location } = this.propshistory.replace('/login', {from: location})}}componentDidMount() {this.getHouseList()}renderHouseItem() {const { list } = this.stateconst { history } = this.propsreturn list.map(item => {return (<HouseItemkey={item.houseCode}onClick={() => history.push(`/detail/${item.houseCode}`)}src={BASE_URL + item.houseImg}title={item.title}desc={item.desc}tags={item.tags}price={item.price}/>)})}renderRentList() {const { list } = this.stateconst hasHouses = list.length > 0if (!hasHouses) {return (<NoHouse>您還沒有房源,<Link to="/rent/add" className={styles.link}>去發布房源</Link>吧~</NoHouse>)}return <div className={styles.houses}>{this.renderHouseItem()}</div>}render() {const { history } = this.propsreturn (<div className={styles.root}><NavHeader onLeftClick={() => history.go(-1)}>房屋管理</NavHeader>{this.renderRentList()}</div>)} }

三個路由規則配置

  • 在App.js 中導入Rent已發布房源列表頁面
  • 在App.js 中導入AuthRoute組件
  • 使用AuthRoute組件,配置路由規則
  • 使用同樣方式,配置Rent/Add 房源發布頁面,Rent/Search 關鍵詞搜索小區信息頁面
{/* 配置登錄后,才能訪問的頁面 */} <AuthRoute exact path="/rent" component={Rent} /> <AuthRoute path="/rent/add" component={RentAdd} /> <AuthRoute path="/rent/search" component={RentSearch} />

搜索模塊(★★★)

關鍵詞搜索小區信息

  • 獲取SearchBar 搜索欄組件的值
  • 在搜索欄的change事件中,判斷當前值是否為空
  • 如果為空,直接return,不做任何處理
  • 如果不為空,就根據當前輸入的值以及當前城市id,獲取該關鍵詞對應的小區信息
  • **問題:**搜索欄中每輸入一個值,就發一次請求,這樣對服務器壓力比較大,用戶體驗不好
  • **解決方式:**使用定時器來進行延遲執行(關鍵詞:JS文本框輸入 防抖)

實現步驟

  • 給SearchBar組件,添加onChange配置項,獲取文本框的值
<div className={styles.root}>{/* 搜索框 */}<SearchBarplaceholder="請輸入小區或地址"value={searchTxt}onChange={this.handleSearchTxt}showCancelButton={true}onCancel={() => history.go(-1)}/>{/* 搜索提示列表 */}<ul className={styles.tips}>{this.renderTips()}</ul> </div>
  • 判斷當前文本框的值是否為空
  • 如果為空,清空列表,然后return,不再發送請求
handleSearchTxt = value => {this.setState({ searchTxt: value })if (!value) {// 文本框的值為空return this.setState({tipsList: []})}}
  • 如果不為空,使用API發送請求,獲取小區數據
  • 使用定時器來延遲搜索,提升性能
handleSearchTxt = value => {this.setState({ searchTxt: value })if (!value) {// 文本框的值為空return this.setState({tipsList: []})}// 清除上一次的定時器clearTimeout(this.timerId)this.timerId = setTimeout(async () => {// 獲取小區數據const res = await API.get('/area/community', {params: {name: value,id: this.cityId}})this.setState({tipsList: res.data.body})}, 500)}

傳遞校區信息給發布房源頁面

  • 給搜索列表項添加點擊事件
// 渲染搜索結果列表renderTips = () => {const { tipsList } = this.statereturn tipsList.map(item => (<likey={item.community}className={styles.tip}onClick={() => this.onTipsClick(item)}>{item.communityName}</li>))}
  • 在事件處理程序中,調用 history.replace() 方法跳轉到發布房源頁面
  • 將被點擊的校區信息作為數據一起傳遞過去
onTipsClick = item => {this.props.history.replace('/rent/add', {name: item.communityName,id: item.community})}
  • 在發布房源頁面,判斷history.location.state 是否為空
  • 如果為空,不做任何處理
  • 如果不為空,則將小區信息存儲到發布房源頁面的狀態中
constructor(props) {super(props)// console.log(props)const { state } = props.locationconst community = {name: '',id: ''}if (state) {// 有小區信息數據,存儲到狀態中community.name = state.namecommunity.id = state.id} }

發布房源

布局結構

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OZjtHyBI-1575112741233)(images/發布房源 -布局結構.png)]

  • List列表 組件
  • InputItem 文本輸入組件
  • TextareaItem 多行輸入組件
  • Picker 選擇器組件
  • ImagePicker 圖片選擇器組件
  • 模板結構
import React, { Component } from 'react'import {Flex,List,InputItem,Picker,ImagePicker,TextareaItem,Modal } from 'antd-mobile'import NavHeader from '../../../components/NavHeader' import HousePackge from '../../../components/HousePackage'import styles from './index.module.css'const alert = Modal.alert// 房屋類型 const roomTypeData = [{ label: '一室', value: 'ROOM|d4a692e4-a177-37fd' },{ label: '二室', value: 'ROOM|d1a00384-5801-d5cd' },{ label: '三室', value: 'ROOM|20903ae0-c7bc-f2e2' },{ label: '四室', value: 'ROOM|ce2a5daa-811d-2f49' },{ label: '四室+', value: 'ROOM|2731c38c-5b19-ff7f' } ]// 朝向: const orientedData = [{ label: '東', value: 'ORIEN|141b98bf-1ad0-11e3' },{ label: '西', value: 'ORIEN|103fb3aa-e8b4-de0e' },{ label: '南', value: 'ORIEN|61e99445-e95e-7f37' },{ label: '北', value: 'ORIEN|caa6f80b-b764-c2df' },{ label: '東南', value: 'ORIEN|dfb1b36b-e0d1-0977' },{ label: '東北', value: 'ORIEN|67ac2205-7e0f-c057' },{ label: '西南', value: 'ORIEN|2354e89e-3918-9cef' },{ label: '西北', value: 'ORIEN|80795f1a-e32f-feb9' } ]// 樓層 const floorData = [{ label: '高樓層', value: 'FLOOR|1' },{ label: '中樓層', value: 'FLOOR|2' },{ label: '低樓層', value: 'FLOOR|3' } ]export default class RentAdd extends Component {constructor(props) {super(props)// console.log(props)const { state } = props.locationconst community = {name: '',id: ''}if (state) {// 有小區信息數據,存儲到狀態中community.name = state.namecommunity.id = state.id}this.state = {// 臨時圖片地址tempSlides: [],// 小區的名稱和idcommunity,// 價格price: '',// 面積size: '',// 房屋類型roomType: '',// 樓層floor: '',// 朝向:oriented: '',// 房屋標題title: '',// 房屋圖片houseImg: '',// 房屋配套:supporting: '',// 房屋描述description: ''}}render() {const Item = List.Itemconst { history } = this.propsconst {community,price,roomType,floor,oriented,description,tempSlides,title,size} = this.statereturn (<div className={styles.root}><NavHeader onLeftClick={this.onCancel}>發布房源</NavHeader>{/* 房源信息 */}<ListclassName={styles.header}renderHeader={() => '房源信息'}data-role="rent-list">{/* 選擇所在小區 */}<Itemextra={community.name || '請輸入小區名稱'}arrow="horizontal"onClick={() => history.replace('/rent/search')}>小區名稱</Item>{/* 相當于 form 表單的 input 元素 */}<InputItemplaceholder="請輸入租金/月"extra="¥/月"value={price}>租&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;金</InputItem><InputItemplaceholder="請輸入建筑面積"extra="㎡"value={size}onChange={val => this.getValue('size', val)}>建筑面積</InputItem><Pickerdata={roomTypeData}value={[roomType]}cols={1}><Item arrow="horizontal">戶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;型</Item></Picker><Pickerdata={floorData}value={[floor]}cols={1}><Item arrow="horizontal">所在樓層</Item></Picker><Pickerdata={orientedData}value={[oriented]}cols={1}><Item arrow="horizontal">朝&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;向</Item></Picker></List>{/* 房屋標題 */}<ListclassName={styles.title}renderHeader={() => '房屋標題'}data-role="rent-list"><InputItemplaceholder="請輸入標題(例如:整租 小區名 2室 5000元)"value={title}/></List>{/* 房屋圖像 */}<ListclassName={styles.pics}renderHeader={() => '房屋圖像'}data-role="rent-list"><ImagePickerfiles={tempSlides}multiple={true}className={styles.imgpicker}/></List>{/* 房屋配置 */}<ListclassName={styles.supporting}renderHeader={() => '房屋配置'}data-role="rent-list"><HousePackge select /></List>{/* 房屋描述 */}<ListclassName={styles.desc}renderHeader={() => '房屋描述'}data-role="rent-list"><TextareaItemrows={5}placeholder="請輸入房屋描述信息"value={description}/></List><Flex className={styles.bottom}><Flex.Item className={styles.cancel} onClick={this.onCancel}>取消</Flex.Item><Flex.Item className={styles.confirm} onClick={this.addHouse}>提交</Flex.Item></Flex></div>)} }

獲取房源數據分析(★★)

  • InputItem、TextareaItem、Picker組件,都使用onChange配置項,來獲取當前值
  • 處理方式:封裝一個事件處理函數 getValue 來統一獲取三種組件的值
    • 創建方法getValue作為三個組件的事件處理函數
    • 該方法接受兩個參數:1. name 當前狀態名;2. value 當前輸入值或者選中值
    • 分別給 InputItem/TextareaItem/Picker 組件,添加onChange配置項
    • 分別調用 getValue 并傳遞 name 和 value 兩個參數(注意:Picker組件選中值為數組,而接口需要字符串,所以,取索引號為 0 的值即可)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ICGMW4Z9-1575112741237)(images/getValue.png)]

示例代碼:

/* 獲取表單數據:*/getValue = (name, value) => {this.setState({[name]: value})}// 給相應組件添加 onChange 事件,傳遞 name 和value

獲取房屋配置數據(★★)

  • 給HousePackge 組件, 添加 onSelect 屬性
  • 在onSelect 處理方法中,通過參數獲取到當前選中項的值
  • 根據發布房源接口的參數說明,將獲取到的數組類型的選中值,轉化為字符串類型
  • 調用setState 更新狀態
/* 獲取房屋配置數據 */ handleSupporting = selected => {this.setState({supporting: selected.join('|')}) }... <HousePackge select onSelect={this.handleSupporting} />

圖片上傳(★★★)

分析

  • 根據發布房源接口,最終需要的是房屋圖片的路徑
  • 兩個步驟: 1- 獲取房屋圖片; 2- 上傳圖片獲取到圖片的路徑
  • 如何獲取房屋圖片? ImagePicker圖片選擇器組件,通過onChange配置項來獲取
  • 如何上傳房屋圖片? 根據圖片上傳接口,將圖片轉化為FormData數據后再上傳,由接口返回圖片路徑

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-clwi2iUG-1575112741238)(images/圖片上傳接口.png)]

獲取房屋圖片

要上傳圖片,首先需要先獲取到房屋圖片

  • 給ImagePicker 組件添加 onChange 配置項
  • 通過onChange 的參數,獲取到上傳的圖片,并且存儲到tempSlides中
handleHouseImg = (files, type, index) => {// files 圖片文件的數組; type 操作類型:添加,移除(如果是移除,那么第三個參數代表就是移除的圖片的索引)console.log(files, type, index)this.setState({tempSlides: files})}...<ImagePickerfiles={tempSlides}onChange={this.handleHouseImg}multiple={true}className={styles.imgpicker}/>

上傳房屋圖片

圖片已經可以通過 ImagePicker 的 onChange 事件來獲取到了,接下來就需要把圖片進行上傳,然后獲取到服務器返回的成功上傳圖片的路徑

  • 給提交按鈕,綁定點擊事件
  • 在事件處理函數中,判斷是否有房屋圖片
  • 如果沒有,不做任何處理
  • 如果有,就創建FormData的示例對象(form)
  • 遍歷tempSlides數組,分別將每一個圖片圖片對象,添加到form中(鍵為:file,根據接口文檔獲取)
  • 調用圖片上傳接口,傳遞form參數,并設置請求頭 Content-Type 為 multipart/form-data
  • 通過接口返回值獲取到圖片路徑
// 上傳圖片 addHouse = async() => {const { tempSlides } = this.statelet houseImg = ''if (tempSlides.length > 0) {// 已經有上傳的圖片了const form = new FormData()tempSlides.forEach(item => form.append('file', item.file))const res = await API.post('/houses/image', form, {headers: {'Content-Type': 'multipart/form-data'}})// console.log(res)houseImg = res.data.body.join('|')} } ... <Flex.Item className={styles.confirm} onClick={this.addHouse}>提交 </Flex.Item>

發布房源

到現在,我們已經可以獲取到發布房源的所有信息了,接下來就需要把數據傳遞給服務器

  • 在 addHouse 方法中, 從state 里面獲取到所有的房屋數據
  • 使用API 調用發布房源接口,傳遞所有房屋數據
  • 根據接口返回值中的狀態碼,判斷是否發布成功
  • 如果狀態碼是200,標示發布成功,就提示:發布成功,并跳轉到已發布的房源頁面
  • 否則,就提示:服務器偷懶了,請稍后再試
addHouse = async () => {const {tempSlides,title,description,oriented,supporting,price,roomType,size,floor,community} = this.statelet houseImg = ''// 上傳房屋圖片:if (tempSlides.length > 0) {// 已經有上傳的圖片了const form = new FormData()tempSlides.forEach(item => form.append('file', item.file))const res = await API.post('/houses/image', form, {headers: {'Content-Type': 'multipart/form-data'}})houseImg = res.data.body.join('|')}// 發布房源const res = await API.post('/user/houses', {title,description,oriented,supporting,price,roomType,size,floor,community: community.id,houseImg})if (res.data.status === 200) {// 發布成功Toast.info('發布成功', 1, null, false)this.props.history.push('/rent')} else {Toast.info('服務器偷懶了,請稍后再試~', 2, null, false)} }

項目打包

目標

  • 能夠配置生產環境的環境變量
  • 能夠完成簡易的打包
  • 知道react中如果要配置webpack的兩種方式
  • 知道 antd-mobile 按需加載的好處
  • 知道路由代碼分割的好處
  • 能夠參照筆記來進行 按需加載配置和代碼分割配置,然后打包
  • 能夠知道如何解決react中跨域問題

簡易打包(★★★)

  • 打開 create-react-app 腳手架的 打包文檔說明
  • 在根目錄創建 .env.production 文件,配置生產環境的接口基礎路徑

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dCBhVvUr-1575112741243)(images/生產環境.jpg)]

  • 在項目根目錄中,打開終端
  • 輸入命令: yarn build,進行項目打包,生成build文件夾(打包好的項目內容)
  • 將build目錄中的文件內容,部署到都服務器中即可
  • 也可以通過終端中的提示,使用 serve-s build 來本地查看(需要全局安裝工具包 serve)

如果出現以下提示,就代表打包成功,在根目錄中就會生成一個build文件夾

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8arTTF5q-1575112741247)(images/build命令.png)]

腳手架的配置說明(★★★)

  • create-react-app 中隱藏了 webpack的配置,隱藏在react-scripts包中

  • 兩種方式來修改

    • 運行命令 npm run eject 釋放 webpack配置(注意:不可逆)

      如果您對構建工具和配置選擇不滿意,您可以eject隨時進行。此命令將從項目中刪除單個構建依賴項。

      相反,它會將所有配置文件和傳遞依賴項(Webpack,Babel,ESLint等)作為依賴項復制到項目中package.json。從技術上講,依賴關系和開發依賴關系之間的區別對于生成靜態包的前端應用程序來說是非常隨意的。此外,它曾經導致某些托管平臺出現問題,這些托管平臺沒有安裝開發依賴項(因此無法在服務器上構建項目或在部署之前對其進行測試)。您可以根據需要自由重新排列依賴項package.json。

      除了eject仍然可以使用所有命令,但它們將指向復制的腳本,以便您可以調整它們。在這一點上,你是獨立的。

      你不必使用eject。策劃的功能集適用于中小型部署,您不應覺得有義務使用此功能。但是,我們知道如果您準備好它時無法自定義此工具將無用

    • 通過第三方包重寫 webpack配置(比如:react-app-rewired 等)

antd-mobile 按需加載(★★★)

  • 打開 antd-mobile 在create-react-app中的使用文檔
  • 安裝 yarn add react-app-rewired customize-cra(用于腳手架重寫配置)
  • 修改package.json 中的 scripts

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8WNqUAqi-1575112741249)(images/scripts配置.png)]

  • 在項目根目錄創建文件: config-overrides.js(用于覆蓋腳手架默認配置)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NfRi4YbM-1575112741254)(images/overrides.png)]

  • 安裝 yarn add babel-plugin-import 插件(用于按需加載組件代碼和樣式)
  • 修改 config-overrides.js 文件,配置按需加載功能
const { override, fixBabelImports } = require('customize-cra'); module.exports = override(fixBabelImports('import', {libraryName: 'antd-mobile',style: 'css',}), );
  • 重啟項目(yarn start)
  • 移除index.js 中導入的 antd-mobile樣式文件
  • 將index.css 移動到App后面,讓index.css 中的頁面背景生效

打完包后,你會發現,兩次打包的體積會有變化,這樣達到了一個代碼體積優化的層面

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-U21VZObR-1575112741257)(images/兩次打包對比.png)]

基于路由代碼分割(★★★)

  • 目的:將代碼按照路由進行分割,只在訪問該路由的時候才加載該組件內容,提高首屏加載速度
  • 如何實現? React.lazy() 方法 + import() 方法、Suspense組件(React Code-Splitting文檔)
  • React.lazy() 作用: 處理動態導入的組件,讓其像普通組件一樣使用
  • import(‘組件路徑’),作用:告訴webpack,這是一個代碼分割點,進行代碼分割
  • Suspense組件:用來在動態組件加載完成之前,顯示一些loading內容,需要包裹動態組件內容

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nR1oGuPt-1575112741259)(images/路由分割.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3qAur6qu-1575112741264)(images/suspense.png)]

項目中代碼修改:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DtzZ8ATO-1575112741269)(images/項目代碼.png)]

其他性能優化(★★)

  • React.js 優化性能文檔

  • react-virtualized只加載用到的組件 文檔

  • 腳手架配置 解決跨域問題

    • 安裝 http-proxy-middleware

      $ npm install http-proxy-middleware --save $ # or $ yarn add http-proxy-middleware
    • 創建src/setupProxy.js并放置以下內容

      const proxy = require('http-proxy-middleware');module.exports = function(app) {app.use(proxy('/api', { target: 'http://localhost:5000/' })); };
    • **注意:**無需在任何位置導入此文件。它在啟動開發服務器時自動注冊,此文件僅支持Node的JavaScript語法。請務必僅使用支持的語言功能(即不支持Flow,ES模塊等)。將路徑傳遞給代理功能允許您在路徑上使用通配和/或模式匹配,這比快速路由匹配更靈活

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zqucj2vu-1575112741271)(images/長列表優化.png)]

好客租房移動Web(下)-總結

  • 登錄模塊:使用Fomik組件實現了表單處理和表單校驗、封裝鑒權路由AuthRoute和axios攔截器實現登錄訪問控制
  • 我的收藏模塊:添加、取消收藏
  • 發布房源模塊:小區關鍵詞搜索、圖片上傳、發布房源信息
  • 項目打包和優化:antd-mobile組件庫按需加載,基于路由的代碼分割實現組件的按需加載,提高了首屏加載速度

總結

以上是生活随笔為你收集整理的react好租客项目Day11-发布房源模块(js输入框防抖图片上传)项目打包项目优化(按需加载路由代码分割)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。