React

七月在夏天-mh發表於2024-05-30

react 依賴

  • react-native 移動端跨平臺
  • 16.13.1版本
  1. react: 核心程式碼
  2. react-dom: 渲染在不同平臺需要的核心程式碼
  3. babel:jsx轉換react程式碼工具
//crossorigin 在控制檯顯示遠端的錯誤資訊
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
 ReactDom.render(<App/>,documnet.getElementById('root'))
</script>
//1有繼承extends,子類必須呼叫super()
class Person {
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
}

class Student extends Person{
    constructor(name,age){
    super(name,age)
}
}
jsx核心語法

書寫規範:

  1. 只能有一個根元素div(或者用Fragment)片段,空標籤佔位
  2. 用小括號包裹
  3. 可以寫雙標籤,或者單標籤,必須/>結尾
{js表示式}

1.註釋書寫:
{/*我是一段註釋*/}

2.在{}中不能顯示,被忽略
test1:null
test2:undefined
test3:Boolean
friend:{
    name:'kobe'
}
this.setState.test3.toString()可以展示在頁面
this.setState.friend //報錯,物件不能直接這樣展示 ,不能作為jsx的子類

3.嵌入表示式
{/*三元表示式*/}
{isLogin?'歡迎':'登入'}

{/*函式呼叫*/}


4.jsx繫結屬性className 
<div className ='' style={{color:'red',fontSize:'30px'}}></div>
<label htmlFor=''></label>
//方式一,顯示繫結
<button  onClick={this.btnClick.bind(this)}></button>


//方式二
this.btnClick=this.btnClick.bind(this)
<button  onClick={this.btnClick}></button>
<button  onClick={(e)=>{this.btnClick(item,index)}}></button>//執行另外一個函式 --推薦
//只要一個引數(e),括號可以省略 e=>{}
    btnClick(item,index){
        
    }

//方式三  推薦
<button  onClick={this.btnClick></button>
const btnClick=()=>{

} 

5.傳遞引數

6.return () 用小括號包裹起來,標籤可以換行

7.條件渲染
  // 1.方案一:透過if判斷: 邏輯程式碼非常多的情況
    let welcome = null;
    let btnText = null;
    if (isLogin) {
      welcome = <h2>歡迎回來~</h2>
      btnText = "退出";
    } else {
      welcome = <h2>請先登入~</h2>
      btnText = "登入";
    }
 {/* 2.方案二: 三元運算子 */}
 <button onClick={e => this.loginClick()}>{isLogin ? "退出" :"登入"}</button>
 
 {/* 3.方案三: 邏輯與&& */}
{/* 邏輯與: 一個條件不成立, 後面的條件都不會進行判斷了 */}
    <h2>{ isLogin && "你好啊, coderwhy" }</h2>
    { isLogin && <h2>你好啊, coderwhy</h2> }

react腳手架:create-react-app 專案名稱(dccweb-hd)不允許大寫字母

npm yarn
npm install yarn install
npm install yarn add

PWA 離線

serviceWork.js

yarn eject 暴露webpack配置資訊 此操作不可逆

元件的生命週期

生命週期 
類元件:可以維護資料狀態,有this
函式沒有生命週期,沒有this,不能管理資料狀態
類裡面的叫方法,有this繫結
外部叫函式

掛載階段 mounting 
constroct
cwm→	componentWillMount = () => { } DEPRECATED!!! 過時的
cdm→	componentDidMount = () => { }  *****

cwr→	componentWillReceiveProps = (nextProps) => { } DEPRECATED!!!

更新階段 Updating
scu→	shouldComponentUpdate = (nextProps, nextState) => { }
cwup→	componentWillUpdate = (nextProps, nextState) => { } DEPRECATED!!!
cdup→	componentDidUpdate = (prevProps, prevState) => { } *****

解除安裝Unmount 
cwun→	componentWillUnmount = () => { } 

元件的資料傳遞

父子元件的通訊
父元件透過屬性=值 prodectList={prodectList}
子元件props引數獲取
function Main(props) {
    const {prodectList}=props


子元件傳遞父元件
父元件 itemClick={函式}
子元件 執行函式

// 父元件裡呼叫子元件 是否允許ppt向下慣性運動
  const flagRef = useRef(true);//是否允許ppt向下慣性運動,預設true,允許,點選一鍵置頂按鈕時,不允許
  const getIsInertiaMove = (val: boolean) => {
    flagRef.current = val;
  };
 <Topping
          parentCallback={getIsInertiaMove}
          currScrollPos={currScrollPosY}
 />
 
 //子元件接收
 interface IToppingProps {
  currScrollPos: any;
  parentCallback: Function;
}
function Topping(props: IToppingProps) {
  const { currScrollPos, parentCallback } = props;
  
   // 觸發一鍵置頂按鈕,不允許向下慣性運動
   parentCallback(false);
  }
  

跨元件通訊
1.props,一級一級傳值
2.屬性展開:jsx語法
const props={firstName='hobby',lastName='Hector'}
<ProfileHeader {...props}/>
<ProfileHeader firstName="Ben" lastName="Hector" />

3.Context:★
類元件
    第一步:建立 export const WordContext = createContext({} as IMobSignContext);
 <WordContext.provider value={}>
    <Profile/> //不包含在這個裡面,傳遞的就是預設值
 <WordContext.provider/>
 第二步:
 ProfileHeader.contextType=WordContext;
 
  this.context

函式元件:
consumer

後續用redux替代 ★






//插槽 slot
<NavBar>
    <span></span>
    <div></div>
</NavBar>


this.props.children 獲取元件內部標籤

跨元件事件傳遞 events

yarn add events
API
建立物件:eventBus
import { EventEmitter } from 'events';
const eventBus = new EventEmitter();

發出事件eventBus.emit("事件名稱",引數列表)
監聽事件eventBus.addListener("事件名稱",監聽函式)
移除事件:eventBus.removeListener("事件名稱",監聽函式)

setState

setState是非同步更新的
提高效能:獲取多個更新,然後批次更新
如果同步,不能保證render和props同步,不能保證state和props一致性

 this.setState({
     message:'你好啊'
 },()=>{
     //拿到非同步的資料,類似vue裡面的nextTick
     console.log(this.state.message)
 })
 componentDidUpdate()方式二:獲取非同步資料
 
 同步更新:
 放在定時器裡面執行,變成同步
 
 
 資料合併:傳物件
 setState內部合併:
 
 累計合併:傳函式
 setState((preState,props)=>{
    return{
        counter:preState.counter+1
    }
 })
 

react效能最佳化

函式元件:memo包裹
counter改變,包裹memo的元件不會重新渲染

類元件:extends PureCompontent


Ref

React.createRef()
current 獲取元素

react中的CSS

CSS in js
yarn add styled-components

style.ts
import styled from 'styled-components';

export const BtnWrapper = styled.div<{ isActive: boolean; activeBgi: any }>`
    border: ${(props) =>props.isActive ? '0.05rem solid #0181ff' : '0.05rem solid red'};
    span{
        &.active{
            color:red //表示同時是span並且有active
        }
    }
`;
<BtnWrapper>
<BtnWrapper/>


react 新增class
/**
 * 特點:
 *  1.props穿透
 *  2.attrs的使用
 *  3.傳入state作為props屬性
 */

const HYInput = styled.input.attrs({
  placeholder: "coderwhy",
  bColor: "red"
})`
  background-color: lightblue;
  border-color: ${props => props.bColor};
  color: ${props => props.color};
`
<HYInput type="password" color={this.state.color}/>

高階用法:
1.繼承 
styled(HYInput)`
`
2.設定主題
import styled {ThemeProvider} from 'styled-components';
<ThemeProvider theme={{themeColor:'red',fontSize:'20px'}}>
<ThemeProvider/>

color: ${(props) =>props.theme.themeColor}
 
 
 動態新增classNames
三元表示式
第三方庫:classNames★

classNames({foor:true})
className={classNames(['clear', { iconActive: isBtnActive }])}

 <div
      className={classnames({
        [styles.sheet]: true,
        [styles.active]: current.sheetId == v.sheetId,
      })}
    >
    
const active = useMemo(
  () =>
  classNames({
      [styles.active]: activeCurrentPage===activeIndex,
    }),
  [activeCurrentPage],
);

  • webpack下,import store from './store/index.js'
  • index.js可以省略。,import store from './store'
  • import * as actionType from './constants'; actionType.
import {
  incAction,
  addAction,
  changeBannersAction,
  changeRecommendAction
} from '../store/actionCreators'

redux

  //★actionCreators
 export const addAction = num => ({
  type: ADD_NUMBER,
  num
});

 //★constants  //export const ADD_NUMBER = "ADD_NUMBER";
 //★index
 
 //★reducer
 // 拆分counterReducer
const initialCounterState = {
  counter: 0
}
function counterReducer(state = initialCounterState, action) {
  switch (action.type) {
    case ADD_NUMBER:
      return { ...state, counter: state.counter + action.num };
    case SUB_NUMBER:
      return { ...state, counter: state.counter - action.num };
    case INCREMENT:
      return { ...state, counter: state.counter + 1 };
    case DECREMENT:
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
  }
}

export default counterReducer;

 
import { useSelector, shallowEqual } from 'react-redux';
import reducer, { defaultState } from './reducer';
import React, {
  memo,
  useRef,
  useState,
  useReducer,
  useContext,
  useCallback,
  useMemo,
  useEffect,
  useLayoutEffect,
} from 'react';



store
const init={
    friend:[
    {name:'why'}
    ]
}
import reducer from './reducer.js';
const store = redux.createStore(reducer);

一般會有多個reducer,需要合併


action
派發(dispatch())action 更新
const action1={type:'ADD_FRIEND',info:{name:'lucy'}}
store.dispatch(action1)


---
---
reducer 純函式,不能產生副作用
reducer將sotre和action 聯絡起來
import {
  ADD_NUMBER,
  SUB_NUMBER,
  INCREMENT,
  DECREMENT
} from './constants.js';

const defaultState = {
  counter: 0
}

function reducer(state = defaultState, action) {
  switch (action.type) {
    case ADD_NUMBER:
      return { ...state, counter: state.counter + action.num };
    case SUB_NUMBER:
      return { ...state, counter: state.counter - action.num };
    case INCREMENT:
      return { ...state, counter: state.counter + 1 };
    case DECREMENT:
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
  }
}

export default reducer;

中介軟體:redux-thunck

hooks

useState
useEffect
useContext
useReducer
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
自定義hooks

useSelector
import { useSelector } from 'umi';
import { useSelector, shallowEqual } from 'react-redux';

★useState  返回一個陣列 
* 元素1: 當前state的值
* 元素2: 設定新的值時,使用的一個函

<React.StricMode>
    <App/>
<React.StricMode/>
嚴格模式下,render會被渲染兩次

注意:不要再函式,條件判斷,for迴圈裡面使用hooks
  const [counter,setCounter]=useState(0) 
  setCounter(counter+1)
  
  傳入函式
const [count, setCount] = useState(() => 10);
 setCount((prevCount) => prevCount + 10);
  
  usestate 快捷鍵,按下tab鍵
  
  
 ★useEffect  生命週期
 
 
  useEffect(() => {
    console.log("訂閱一些事件");
    
    //生命週期 componentWillUnmount
    return () => {
      console.log("取消訂閱事件")
    }
  }, []);
    []表示第一次渲染的時候執行一次;如果不寫,只要元件重新渲染,都會執行一遍

 ★useContext 子孫元件傳遞資料
 export const UserContext= createContext()
 export const PcSignContext = createContext({} as IPcSignContext);
  {/* <UserContext.Provider value={{name: "why", age: 18}}>
        <TokenContext.Provider value="fdafdafafa">
          <CustomContextShareHook/>
        </TokenContext.Provider>
      </UserContext.Provider> */}
 
 
  const user = useContext(UserContext);
  const theme = useContext(ThemeContext);



★useReducer  是useState的一種替代方案 不共享state
  const [state, dispatch] = useReducer(reducer, {counter: 0});
  dispatch({type: "increment"})}

export default function reducer(state, action) {
  switch(action.type) {
    case "increment":
      return {...state, counter: state.counter + 1};
    case "decrement":
      return {...state, counter: state.counter - 1};
    default:
      return state;
  }
}


★useCallback 效能最佳化 針對函式 meno
場景: 在將一個元件中的函式, 傳遞給子元素進行回撥使用時, 使用useCallback對函式進行處理.
 const increment2 = useCallback(() => {
    console.log("執行increment2函式");
    setCount(count + 1);
  }, [count]);
//也可以用useMome
  const increment3 = useMemo(() => {
    return () => {
      console.log("執行increment2函式");
      setCount(count + 1);
    }
  }, [count]);

★useMemo  效能最佳化 針對返回值,返回記憶值
複雜計算的應用
  const total = useMemo(() => {
    return calcNumber(count);
  }, [count]);
  
  
傳入子元件  或者用useState
  const info = useMemo(() => {
    return { name: "why", age: 18 };
  }, []);
  <HYInfo info={info} />
  
  
 ★useRef 只能在class元件中使用,在函式式元件中使用需要用forwardRef包裹
   const titleRef = useRef();
   
function changeDOM() {
    titleRef.current.innerHTML = "Hello World";
    inputRef.current.focus();
    console.log(testRef.current);
    console.log(testRef2.current);
  }

    <h2 ref={titleRef}>RefHookDemo01</h2>
    
    *** const numRef = useRef(count);
      useEffect(() => {
        numRef.current = count;
      }, [count])
    //儲存一個函式,在整個生命週期中儲存不變
    使用場景:記錄上一次的值
    
    
    
★useImperativeHandle 和forwardRef關聯 目的不過多暴露給父元件
forwardRef 可以將ref轉發到子元件

const HYInput = forwardRef((props, ref) => {
  const inputRef = useRef();

//()用小括號包裹起來,返回的是一個物件
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }), [inputRef])

  return <input ref={inputRef} type="text"/>
})


export default function UseImperativeHandleHookDemo() {
  const inputRef = useRef();

  return (
    <div>
      <HYInput ref={inputRef}/>
      <button onClick={e => inputRef.current.focus()}>聚焦</button>
    </div>
  )
}


★useLayoutEffect  佈局作用,阻塞瀏覽器的更新    // 稍稍阻塞瀏覽器的重繪,儘可能刪除存在滯留隱患的監聽器

useEffect 不會阻塞dom更新,dom更新完畢之後執行


export default function LayoutEffectCounterDemo() {
  const [count, setCount] = useState(10);
    //頁面不會閃0,如果用useEffect ,頁面是先出現0,在出現隨機數
  useLayoutEffect(() => {
    if (count === 0) {
      setCount(Math.random() + 200)
    }
  }, [count]);

  return (
    <div>
      <h2>數字: {count}</h2>
      <button onClick={e => setCount(0)}>修改數字</button>
    </div>
  )
}






★自定義hoos 相同邏輯抽取到一個裡面,

const Profile = (props) => {
  useLoggingLife("Profile");
  return <h2>Profile</h2>
}
//普通函式不能使用hook,只能在自定義hook中使用,use開頭就代表自定義hook
function useLoggingLife(name) {
  useEffect(() => {
    console.log(`${name}元件被建立出來了`);

    return () => {
      console.log(`${name}元件被銷燬掉了`);
    }
  }, []);
}


//Context共享
export function usePptContext() {
  const context = useContext(PptContext);
  return context;
}

//獲取滾動位置
function useScrollPosition() {
  const [scrollPosition, setScrollPosition] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      setScrollPosition(window.scrollY);
    }
    document.addEventListener("scroll", handleScroll);

    return () => {
      document.removeEventListener("scroll", handleScroll)
    }
  }, []);

  return scrollPosition;
}

const position = useScrollPosition();


★useSelector
const { banners, recommends, counter } = useSelector(state => ({
    banners: state.banners,
    recommends: state.recommends,
    counter: state.counter
  }), shallowEqual);

專案

yarn add normalize.css
reset.css
@import "~normalize.css"; //從模組裡匯入
@import "~antd/dist/antd.css";

配置別名: yarn add @craco/craco

"scripts": {
    "start": "craco start",
    "build": "umi build",
  },

匯入檔案處理:
最上面第三方的東西
中間匯入功能類的東西,比如網路請求,actionCreators,utils
最後匯入元件

分號儘量加上

專案裡引入redux(24節,一小時)
yarn add redux react-redux redux-thunk 3個依賴
react-redux:作用把react元件和redux結合起來,其中最重要的conText 和Provider
 store/index.js 建立store 
★store

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

//除錯工具生效 如果有就使用,否則使用compose 
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(reducer, composeEnhancers(
  applyMiddleware(thunk)
));

export default store;


一般會有多個reducer,需要合併


★reducer: store/ireducer.js 
import { combineReducers } from 'redux-immutable';//用redux-immutable',在useSelector中取值,用getIn方式
//import { combineReducers } from 'redux';

import { reducer as recommendReducer } from '../pages/discover/c-pages/recommend/store';
import { reducer as playerReducer } from '../pages/player/store';

const cReducer = combineReducers({
  recommend: recommendReducer,
  player: playerReducer
});

export default cReducer;

App.js
import { Provider } from 'react-redux';
import store from './store';
//Provider共享出去,然後透過connect獲取store裡面的state,disPatch類似的東西
  <Provider store={store}>
      <HashRouter>
        <HYAppHeader />
        <Suspense fallback={<div>page loading</div>}>
          {renderRoutes(routes)}
        </Suspense>
        <HYAppFooter />
        <HYAppPlayerBar/>
      </HashRouter>
    </Provider>


★actionCreatios:
export const getLyricAction = (id) => {
  return dispatch => {
    getLyric(id).then(res => {
      const lyric = res.lrc.lyric;
      const lyricList = parseLyric(lyric);
      dispatch(changLyricListAction(lyricList));
    })
  }
}

constants
index
reducer


redux hooks
useDispatch()

//拿到裡面的值,第一個是一個回撥函式
//shallowEqual效能最佳化,淺層比較
 // redux
  const {
    htmlName,
    currentPage,
    pageCount,
    applicationType,
  } = useSelector(
    (state: { app: Application; appstate: AppState }) => ({
      htmlName: state.app.param.htmlName,
      currentPage: state.appstate.currentPage,
      pageCount: (state.app.doc as WpDocument).pageCount,
      currentPagesSize: state.appstate.currentPagesSize,
      applicationType: state.app.param.applicationType,
    }),
    shallowEqual,
  );

★ImmutableJS //最佳化,提高效能,節省記憶體空間,只要修改會返回新的物件,舊的物件不發生變化

 const im = Immutable;
 
    // Map的使用
    // const info = {
    //   name: "kobe",
    //   age: 30,
    //   friend: {
    //     name: "james",
    //     age: 25
    //   }
    // }

    // const infoIM = im.Map(info);//改成Immutable物件

    // const obj = infoIM;
    // const infoIM2 = infoIM.set("name", "why");
    // console.log(obj.get("name"));
    // console.log(infoIM2.get("name"));

    // List的使用
    // const names = ["abc", "cba", "nba"];
    // // const arr = names;
    // // names[0] = "why";
    // // console.log(arr);
    // const namesIM = im.List(names);//改成Immutable物件
    // const arrIM = namesIM.set(0, "why");
    // console.log(namesIM.get(0));//abc 舊的
    // console.log(arrIM.get(0));//why 新的

 
 const info = {
      name: "kobe",
      age: 30,
      friend: {
        name: "james",
        age: 25
      }
    }

// const infoIM = im.Map(info);//改成Immutable物件 ,淺層轉換
const infoIM = im.fromJS(info);//深層巢狀也會轉換Immutable物件 ct
console.log(infoIM.get("friend"));


引入專案
//Map比fromJS效能更高
import { Map ,fromJS} from 'immutable';

import * as actionTypes from './constants';

const defaultState = Map({
  topBanners: [],

  upRanking: {},
});

function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_TOP_BANNERS:
      return state.set("topBanners", action.topBanners);//返回新的資料
    case actionTypes.CHANGE_UP_RANKING:
      return state.set("upRanking", action.upRanking); 
    default:
      return state;
  }
}

export default reducer;

取值:
// redux hook
  const { 
    currentSong, 
    sequence, 
    lyricList,
    currentLyricIndex
  } = useSelector(state => ({
    currentSong: state.getIn(["player", "currentSong"]),
    sequence: state.getIn(["player", "sequence"]),
    lyricList: state.getIn(["player", "lyricList"]),
    currentLyricIndex: state.getIn(["player", "currentLyricIndex"])
  }), shallowEqual);
  const dispatch = useDispatch();

路由

yarn add react-router-dom

import { renderRoutes, matchRoutes } from 'react-router-config';//將所有的路由統一管理
import {
  BrowserRouter,
  Link,
  Route,
  NavLink,
  Switch,
  withRouter
} from 'react-router-dom';

元件裡寫法:
<NavLink exact to="/about" activeClassName="about-active">企業歷史</NavLink>
<NavLink exact to="/about/culture" activeClassName="about-active">企業文化</NavLink>
<NavLink exact to="/about/contact" activeClassName="about-active">聯絡我們</NavLink>

<NavLink exact to="/" activeClassName="link-active">首頁</NavLink>
<NavLink to="/about" activeClassName="link-active">關於</NavLink>
<NavLink to="/profile" activeClassName="link-active">我的</NavLink>
<NavLink to="/abc" activeClassName="link-active">abc</NavLink>
<NavLink to="/user" activeClassName="link-active">使用者</NavLink>
<NavLink to={`/detail/${id}`} activeClassName="link-active">詳情</NavLink>
<NavLink to={`/detail2?name=why&age=18`} activeClassName="link-active">詳情2</NavLink>
<NavLink to={{
          pathname: "/detail3",
          search: "name=abc",
          state: info
         }} 
        activeClassName="link-active">
  詳情3
</NavLink>

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/profile" component={Profile} />
  <Route path="/:id" component={User} />
  <Route path="/user" component={User} />
  <Route path="/login" component={Login} />
  <Route path="/product" component={Product} />
  <Route path="/detail/:id" component={Detail} />
  <Route path="/detail2" component={Detail2} />
  <Route path="/detail3" component={Detail3} />
  <Route component={NoMatch} />
<Switch/>

  {renderRoutes(this.props.route.routes)}// 子路由
  父頁面裡面寫法:
  {renderRoutes(routes)}
  
export default withRouter(App);


  <BrowserRouter>
    <App/>
  </BrowserRouter>
  
  BrowserRouter使用history模式
  HashRouter使用hash模式
動態路由/$(id)

this.props.location

const routes = [
  {
    path: "/",
    exact: true,//精確匹配
    component: Home
  },
  {
    path: "/about",
    component: About,
    routes: [
      {
        path: "/about",
        exact: true,
        component: AboutHisotry
      },
      {
        path: "/about/culture",
        component: AboutCulture
      },
    ]
  },
  {
    path: "/profile",
    component: Profile
  },
  {
    path: "/user",
    component: User
  }
]

axios網路請求 封裝

  • 傳送請求
  • 建立例項
  • 攔截器
  • 請求封裝
    get,post,head,
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';

interface IResponse {
  data: any;
  errorcode: number;
  message: string;
}

const instance = axios.create({
  timeout: 60000
});

instance.interceptors.request.use((config) => {
  // 請求文件資料的攔截
  // if (config.url?.includes('index.json')) {
  //   eventBus.emit('reqSent', '請求文件資料中...');
  // }
  // 發起籤批提交請求的攔截
  if (config.url?.includes('index.json')) {
    // console.log(config,'config.url')
    // eventBus.emit('reqSent', '伺服器解析籤批資料中...');
  }
  return config;
});

// instance.interceptors.response.use((res: AxiosResponse<IResponse>) => {
//   const { status, statusText } = res;
//   const { data, message, errorcode } = res.data;
//   if (
//     errorcode === 0 ||
//     message === '操作成功' ||
//     status.toString().startsWith('2') ||
//     statusText === 'OK'
//   ) {
//     // 延遲測試
//     // setTimeout(() => {
//     // }, 1000);
//     // eventBus.emit('reqSucceeded');
//   } else {
//     // eventBus.emit('reqFailed');
//   }
//   // console.log(res);
//   return res;
// });

//請求失敗,自動重新傳送請求
instance.interceptors.response.use(null, function axiosRetryInterceptor (error) {
    error.config.__retryCount = error.config.__retryCount || 0
    error.config.__retryCount += 1
    if (error.config.__retryCount >= 4) {
        console.log(error.config.__retryCount,'error.config.__retryCount')
      console.log(`url:${error.config.url}重發達到最大次數,停止重發`)
      return Promise.reject(error)
    } else {
        location.reload();
    //     console.log(`url:${error.config.url}開始重發,次數:${error.config.__retryCount},狀態:${error.status},data:${JSON.stringify(error.config)}`)
    //     return new Promise(function (resolve) {
    //         return setTimeout(function () {
    //       return resolve(axios(error.config))
    //     }, 1000)
    //   })
    }
  })

// get封裝
export function get(url: string, params = {}) {
  return new Promise((resolve, reject) => {
    instance({
      url: url,
      params,
      method: 'get',
    })
      .then((res) => {
        if (res.status === 200) {
          resolve(res.data);
        } else {
          reject(res);
        }
      })
      .catch((err) => {
        reject(err)
      });
  });
}

// post封裝
export function post(
  url: string,
  params = {},
  data = {},
  // 進一步配置其他項
  otherConfigs = {} as AxiosRequestConfig,
) {
  return new Promise((resolve, reject) => {
    instance({
      url,
      method: 'post',
      params,
      data,
      ...otherConfigs,
    })
      .then((res) => {
        const { data } = res;
        const { status, statusText } = res;
        if (
          data.errorcode === 0 ||
          data.message === '操作成功' ||
          status.toString().startsWith('2') ||
          statusText === 'OK'
        ) {
          resolve(data);
        } else {
          reject(data);
        }
      })
      .catch((err) => {
        reject(err);
      });
  });
}

// head封裝
export function head(url: string, params = {}) {
  return new Promise((resolve, reject) => {
    instance({
      url: url,
      params,
      method: 'head',
    })
      .then((res) => {
        if (res.status === 200) {
          resolve(res.data);
        } else {
          reject(res);
        }
      })
      .catch((err) => {
        reject(err);
      });
  });
}

export default {
  get,
  post,
  head,
};

import service from './request'
  let resp =await service.get(url)

相關文章