前端面試錦集之 react 萬字長文面試總結

一、react 面試題

  1. redux 中間件的原理的理解,答案如下所示:
  • redux 是一個應用數據流框架,主要是解決了組件間狀態共享的問題,原理是集中式管理,主要有三個核心方法,actionstorereducer
  • 工作流程是 view 調用 storedispatch 接收 action 傳入 storereducer 進行 state 操作,view 通過 store 提供的 getState 獲取最新的數據
  • 新增 state,對狀態的管理更加明確,通過 redux,流程更加規範了,減少手動編碼量,提高了編碼效率,同時缺點時當數據更新時有時候組件不需要,但是也要重新繪製,有些影響效率。一般情況下,我們在構建多交互,多數據流的複雜項目應用時纔會使用它們
  • 常用的一些 redux 中間件,如下所示:
    • redux-thunk:處理異步操作
    • redux-saga:處理異步操作
    • redux-promise:處理異步操作,actionCreator 的返回值是promise
  • 中間件的執行原理和koa中間件的執行原理類似,但是不是洋蔥型的,而是半個洋蔥,因爲redux是單向執行的。當你應用了中間件,在觸發一個action操作的時候,action操作就會經過先經過中間件,最終再形成dispatch(action)。一個觸發一個action動作的時候,代碼的執行邏輯。thunk是允許dispatch一個函數,而不是一個對象
  • thunk中間件的內部,代碼如下所示:
function createThunkMiddleware(extraArgument) {

  return ({ dispatch, getState }) => next => action => {
    // 如果是函數,就執行函數
    if (typeof action === 'function') {
        return action(dispatch, getState, extraArgument);
    }
    // 如果不是,執行下一個中間件
    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

  • 中間件的內部邏輯,代碼如下所示:
const store = createStore(reducer, preloadedState, enchancer);

// 如果沒有中間件,正常觸發一個action;
// 如果有中間件的時候 creatStore內部的執行邏輯是這樣的
// enchancer 就是你應用的中間件,調用applyMiddleware得到的組合中間件

function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
  
    // 該創建的store還是要創建的,只傳入了兩個參數,沒有中間件,得到的是正常的store
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    // 把getState、dispatch傳給中間件
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    // 下面方法返回來了一個函數數組,中間件被剝離到
    // next => {}
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 再執行下面的,中間件就被剝離到
    // action => {}
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

// 下面得到的結果是 
// 假設中間件爲 a b
// a(b(store.dispatch))
return enchancer(createStore)(reducer, preloadedState)// 結合上面thunk的源碼{ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
        return action(dispatch, getState);
    }
    return next(action);
  };

  • 經過上面的操作後,經過中間件包裝後的store的樣子,假設中間件爲 a b c,每一箇中間件配發了一個原始storedispatch,中間件函數嵌套執行,如下所示
    • 沒有中間件,代碼如下
      store = {
          dispatch,
          ... ...,
          subscribe,
          getState
      }
      
      
    • 經過中間包裝後,代碼如下
      store = {
          dispatch: a(b((store.dispatch))),
          ... ...,
          subscribe,
          getState
      }
      
      
  • redux-thunk就是一個封裝函數,允許store.dispatch一個函數,compsoe內部,如下所示:
// compose本身並不改變函數的執行,將函數組合後又返回了一個函數
    function compose(...funcs) {
      if (funcs.length === 0) {
        return arg => arg
      }
      if (funcs.length === 1) {
        return funcs[0]
      }
        return funcs.reduce((a, b) => (...args) => a(b(...args)))
    }

  1. 你會把數據統一放到 redux 中管理,還是共享數據放在 redux 中管理,答案如下所示:
  • 不是react native,所有數據都要放在redux中管理。如果只是把共用的數據放在redux中,一個組件中會既有state、props和redux存儲數據,那麼當頁面出現問題,要從state、props和redux三個方面檢查,開發程序是很快的,但是最費時間的是程序後期的可維護性和代碼的可調節性。如果數據都放在redux中管理,項目出錯以後,就只用檢查redux,定位錯位很快。不要想着state中的數據只會供一個組件使用,在項目越來越大的時候,說不準別的組件會需要使用,redux中可以存儲5GB的數據。所以,能用redux的時候一定要用redux,對於後期的維護來說很方便

  • immutable,當你把reduximmutable這個庫結合使用的時候,你整個項目的性能會達到最優,而且非常非常簡單。沒有數據臃腫的顧慮,你不存在redux中,你也需要存儲在state或者props中。

  1. componentWillReceiveProps 的調用時機,答案如下所示:
  • 父組件中改變了props傳值時觸發的函數
  • props改變的時候纔會調用,父組件第一次往子組件傳值的時候,不會調用
  1. react 性能優化的最佳實踐,答案如下所示:
  • PureComponent,自帶shouldcomponentupdate,是一個淺比較,代碼如下所示:
class Test extends React.PureComponents {
    constructor(props) {
        super(props)
    }
    
    render() {
        return <div>hello</div>
    }
}
  • 通過與immutable.js庫的結合,完美的解決react的性能問題
  • 優化的核心是減少不必要的渲染
  • 增加shouldComponentUpdate鉤子對新舊propsstate進行比較,如果值相同則阻止更新,避免不必要的渲染,或者使用PureReactComponent替代Component,其內部已經封裝了shouldComponentUpdate的淺比較邏輯
  • 對於列表或其他結構相同的節點,爲其中的每一項增加唯一key屬性,以方便Reactdiff算法中對該節點的複用,減少節點的創建和刪除操作
  • render函數中減少類似onClick={() => {doSomething()}}的寫法,每次調用render函數時均會創建一個新的函數,即使內容沒有發生任何變化,也會導致節點沒必要的重渲染,建議將函數保存在組件的成員對象中,這樣只會創建一次
  • webpack-bundle-analyzer分析當前頁面的依賴包,是否存在不合理性
  1. 虛擬dom的理解,虛擬dom會提升代碼性能的原因,答案如下所示:
  • 虛擬dom就是真實dom的一個js對象
  • 以前需要兩個頁面的差異,需要去比對真實dom的比對,真實的dom節點會有事件,屬性,還會有各種各樣的方法。所以兩個真實dom的比對會非常耗性能。於是把dom對象變成js對象,js對象就沒有dom對象上亂七八糟的特性了,js對象就比較快。
  1. webpack中,藉助loader完成的JSX代碼的轉化,還是babel,答案如下所示:
  • babel - preset-react 所去完成的轉化
  1. 調用setState後,發生的過程,答案如下所示:
  • 調用setState函數之後,react會將傳入的參數對象與組件當前的狀態合併,然後觸發調和過程(Reconciliation),以高效方式根據新的狀態構建React元素樹並且着手重新渲染整個UI界面
  • React 得到元素樹之後,React 會自動計算出新的樹與老樹的節點差異,然後根據差異對界面進行最小化重渲染,按需渲染,不是全部渲染
  • 調用函數,通過一個函數返回一個對象,代碼如下所示:
this.setState({
    age: this.state.age + 1
}) // 如果是連續點擊一個按鈕調用這個setState,會出現數值不是一個一個加上去的,而是會出現一次幾個的變化,因爲react會把多個setState整合爲一個,最後在改變state。

this.setState((prevState) => ({
    age: ++ prevState.age
})) // 不管你怎麼瘋狂的點擊按鈕,都會一個一個往上加。
  1. setState是異步的,這個點你在什麼時候遇到過坑,答案如下所示:
  • 使用setState的時候返回傳一個函數,同上所示
  • 對於setState 是異步還是同步主要看是誰在調用它,大部分情況下是異步的,小部分情況是同步的
  • 異步的情況,如下所示:
    • React 代理的合成事件中調用,如 onClick、onChange 事件,這些事件都是 React 爲了代理原生事件而封裝出來的一整套事件機制,我們稱之爲合成事件
    • 在鉤子函數(生命週期)中調用
    • setState 的異步不是真的異步,setState 本身的執行過程是同步的,是 React 將多個 setState 進行合併和批量更新,導致其看起來像是異步的
  • 同步的情況,如下所示:
    • 在原生事件中調用,代碼如下:

             class App extends React.Component{
            ...componentDidMount(){
                document.querySelector('#A').addEventListener('click',()=>{
                    this.setState({
                        // 這裏的 setState 是同步的
                    })
                })
              }
            }
      
    • 在setTimeout()中調用

  1. refs的作用是什麼,你在什麼業務場景下使用過refs,答案如下所示:
  • refs的作用是操作dom,訪問 DOM 元素或者某個組件實例
  • 在業務場景下使用過refs,展示一個圖片,獲取圖片的寬高,這也是因爲react不能直接操作dom
  • 放大鏡,獲取圖片寬高等等
  • 當頁面滾動,監聽頁面滾動的事件,代碼如下所示:
class Test extends Component {
    // 需求:當頁面滾動,監聽頁面滾動的事件
    constructor(props) {
        super(props);
        this.state = {
            top: 0
        }
        this.handleWindowScroll = this.handleWindowScroll.bind(this)
    }
    
    handleWindowScroll() {
        this.setState(() => ({
            top: document.body.scrollTop
        }))
    }
    
    componentDidMount() {
        window.addEventListener('scroll', this.handleWindowScroll)
    }
    
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleWindowScroll)
    }
    
    render() {
        return <div>{this.state.top}</div>
    }
}
  1. ref是一個函數,好處是什麼,答案如下所示:
  • 方便react在銷燬或者重新渲染組件的時候去有效的去清空ref裏面的東西,防止內存泄漏,以後ref不要用字符串的形式了,要用函數式的寫法
  • 代碼如下所示:
class Test extends Component {
  componentDidMount() {
    this.elem
  }

  render() {
    return <div ref={(div) => { this.elem = div }}></div> // ref使用的時候最好使用函數
  }
}
  1. 高階組件的理解,它的本質是什麼,答案如下所示:
  • react裏面不要去使用繼承,爲什麼,設計模式中有這樣一句話“組合優於繼承”,react這種組件式的編程,是一種組合類型的設計模式,一定是優於繼承的,可維護性是比繼承高的多,react中所有問題都是可以利用組件拼合的方法解決的。
  • 高階組件實際上就是一個函數,接收參數,返回參數。對一個組件進行包裝,然後再返回一個組件。爲什麼對一個組件進行包裝呢,因爲組件有可能很多地方要用,這個組件的大部分東西在別的地方都可以直接用,只有少數的地方有區別,我們就可以把共用的地方寫到高階組件裏面去,而通過往高階組件裏面傳遞參數,來去動態這個組件在使用時的差異。
  • 高階組件地獄,新版本的hook解決了這個問題,代碼如下所示:
<A>
  <B>
    <C>
      <D />
    </C>
  </B>
</A>
  • 高階組件其實就是一個函數而已,只不過參數是一個組件而已,返回了一個新的組件。複用組件的業務邏輯 react-redux connect 其實就是一個高階組件。HOC 是純函數,沒有副作用。純函數是輸入確定,輸出就一定確定
  1. 受控組件和非受控組件的區別,答案如下所示:
  • HTML中,類似 <input/>, <select> 和 <textarea> 這樣的表單元素會維護自身的狀態,並基於用戶的輸入來更新。當用戶提交表單時,前面提到的元素的值將隨表單一起被髮送。但在 React 中會有些不同,包含表單元素的組件將會在 state 中追蹤輸入的值,並且每次調用回調函數時,如 onChange 會更新 state,重新渲染組件。一個輸入表單元素,它的值通過 React 的這種方式來控制,這樣的元素就被稱爲"受控元素"
  • 受控組件:這個組件的改變完全受控於數據的變化,數據變了,頁面變了
  • 非受控組件:input框,我直接操作dom,我不讓他進行數據的綁定,輸入完成點擊按鈕的時候,我直接通過refsdom上的內容來進行操作,不是通過數據來控制
  • 受控組件一定是更好的。react是一個數據驅動的框架,所以數據驅動是react核心,所以組件都應該被數據控制
  1. 函數組件和hooks,答案如下所示:
  • Hooks 技術,其作用讓函數組件變得強大起來,它可以讓 react 函數組件也擁有狀態,讓我們用現有的 JavaScript 技術就能快速上手,讓我們獲取數據、更改狀態是如此的輕鬆
  • 使用 Hook 操作數據狀態相比類組件更簡潔,這也是函數式編程的魅力
  • 關於 Hooks 的內容比較多,比如常用的三個基本 Hook 功能:useState、useEffect、useContext,以及額外的方法:useRef、useReducer、useMemo、useCallback、useLayoutEffect、useDebugValue
  1. this指向問題的解決方法,答案如下所示:
  • 行間定義事件後面使用bind綁定this,這一種方法使用bind來修改this的指向,需要注意的是bind括號內第一個參數是修改this的,後面可以設置其他參數進行傳值,代碼如下所示:
	run(){
	        alert("第一種方法!")
	}

  	<button onClick={this.run.bind(this)}>第一種</button>

  • 在構造函數內部聲明this指向,和第一種方法原理一樣,只是寫的位置不同,代碼如下所示:
constructor(props) {
        super(props);
        this.state={
            //定義數據
        }
        this.run = this.run.bind(this);
    }
    
     run(){
            alert("第二種方法!")
      }
      
     <button onClick={this.run}>第二種</button>
  • 聲明事件時將事件等於一個箭頭函數,將定義的run方法再等於一個箭頭函數,利用箭頭函數沒有自己的this指針會繼承外層的作用域這個特性,來解決this指向問題,代碼如下所示:
run=()=> {
	alert("第三種方法!")
  }

<button onClick={this.run}>第三種</button>
  • 行間定義事件使用箭頭函數,和第三種方法的原理是一樣的,只是寫法不同,代碼如下所示:
 run(){
	alert("第四種方法!")
  }

<button onClick={()=>this.run()>第四種</button>

  1. 函數組件怎麼做性能優化,答案如下所示:
  • 函數式組件性能比普通組件性能高,因爲函數組件沒有類的其他屬性,沒有構造類的過程
  • 函數式組件,props發生變化以後,函數就會重新執行,React.memo(function Test() { return <div>123</div> }),這樣包裝,組件就會有shoulComponentUpdate這樣的屬性,這樣函數式組件的性能一定要不普通組件的性能要好的
  • 函數式組件沒有類的構造,生命週期,直接執行就可以,代碼如下所示:
function Test() {
  return <div>123</div>
}

16.在哪個生命週期裏發送ajax,答案如下所示:

  • 一定要在componentDidMount中去發送
  • componentWillMount在新版本的react中已經被廢棄了,取而代之的是一個getDerivedStateFromProps這樣一個生命週期函數,所以用componentWillMount不合適
  • 在用ssr項目中的時候,componentWillMount要做服務端數據的獲取,所以不能被佔用
  1. ssr的原理是什麼,答案如下所示:
  • SSR,服務端渲染,React 代碼在服務端上運行,直接生成帶有數據的 HTML 頁面( ajax 請求均在服務器上完成 ),然後直接將該頁面返回給客戶端,客戶端只需解析 HTML 就能展示頁面
  • 服務端渲染的優點,如下所示:
    • 更好的 SEO,因爲在後端有完整的 HTML 頁面,所以爬蟲更容易爬取關鍵信息
    • 首屏渲染速度快,用戶體驗更好
    • 無需佔用客戶端資源,即解析模板的工作完全交由後端來做,客戶端只要解析標準的 HTML 頁面即可,這樣對於客戶端的資源佔用更少,尤其是移動端,也可以更省電
    • 後端生成生成緩存片段,這樣就可以減少數據庫查詢浪費的時間了,且對於數據變化不大的頁面非常高效
  • 服務端渲染的缺點,如下所示:
    • 不利於前後端分離,開發效率低。使用服務器端渲染,則無法進行分工合作,則對於前端複雜度高的項目,不利於項目高效開發
    • 服務器壓力變大,因爲 React 代碼由服務端執行並生成完成頁面,當外部訪問量增多,可能會出現頁面加載變慢( 請求阻塞 )等情況,此時可以通過負載均衡策略解決
  • 適合 SSR 的項目,如下所示:
    • 項目要求SEOSSR 就很合適 ( 關於 SEO,預渲染也能做到 )
    • 需求項目某頁面首屏時間要求很快,SSR 可以減少白屏時間
    • 首屏頁數據請求多
  • react 服務端渲染的流程,如下所示:
    • 打包階段會將業務代碼打包兩次,一份部署在服務端,一份用於客戶端(可傳到cdn
    • 然後啓動服務,基於用戶請求的路由決定render哪個頁面,主要用到renderToStringapipage組件轉化爲html標記
    • 最簡單的情況,將html標記直接返回客戶端,渲染一個靜態頁面
    • 但實際業務中,一般在服務端需要獲取數據,根據數據來生成html,這種情況下,當在客戶端重新render時,如何保證數據一致呢,解決辦法是將服務端獲取到的數據以字符串的形式返回給客戶端,客戶端渲染的時候直接以該數據進行渲染,保證數據的一致性,進而保證了ui的一致性
    • 當在客戶端運行時,主要用hydrateapihtml標記與js代碼重新結合,之後就與服務端完全沒關係了,可以當spa的情況處理
  • react 中實現 SSR 的核心原理,就是虛擬 DOM 的存在
  1. redux-saga的設計思想的理解,以及sideEffects 的理解,答案如下所示:
  • redux設計思想,web應用是一個狀態機,視圖與狀態是一一對應的,所有的狀態保存在一個對象裏面
  • saga的應用整體思路,使用了Saga後,react只負責數據如何展示,redux來負責數據的狀態和綁定數據到react,而Saga處理了大部分複雜的業務邏輯
  • app.js入口文件引入saga以及reducers,動態執行saga語句 middleware.run(sagas) 必須要在store創建好之後才能執行,在 store 之前執行,程序會報錯。rootsage爲所有模塊組件的sage集合,用sage 副作用的all方法同時併發發出。引入action組件,發出action中定義好的action,用saga副作用處理函數 takeLatest(類似於防抖),執行最後一次請求。reducer文件對需要更改返回stateaction進行處理
  • redux-saga 就是 redux 的一箇中間件,用於更優雅地管理副作用(side effects),redux-saga可以理解爲一個和 系統交互的 常駐進程,可簡單定義爲 saga = Worker + Warcher
  • effect 是一個普通的 javascript對象,包含一些指令,這些指令最終會被 redux-saga 中間件 解釋並執行。在 redux-saga 世界裏,所有的 Effect 都必須被 yield 纔會執行。原則上來說,所有的 yield 後面也只能跟Effect,以保證代碼的易測性,taskgenerator 方法的執行環境,所有sagagenerator方法都跑在task
  • 作用是用於更優雅地管理副作用, 在前端就是異步網絡請求;本質就是爲了解決異步action的問題
  • 優點,如下所示:
    • 副作用轉移到單獨的saga.js中,不再摻雜在action.js中,保持 action 的簡單純粹,又使得異步操作集中可以被集中處理,對比redux-thunk
    • redux-saga 提供了豐富的 Effects,以及 sagas 的機制(所有的 saga 都可以被中斷),在處理複雜的異步問題上更順手。提供了更加細膩的控制流
    • 對比thunkdispatch 的參數依然是一個純粹的 action (FSA)
    • 每一個 saga 都是 一個 generator function,代碼可以採用 同步書寫 的方式 去處理 異步邏輯(No Callback Hell),代碼變得更易讀
    • 同樣是受益於 generator functionsaga 實現,代碼異常/請求失敗 都可以直接通過 try/catch 語法直接捕獲處理
  1. reactjqueryvue是否有可能共存在一個項目中,答案如下所示:
  • 完全可以共存,關鍵看怎麼共存
  1. 組件是什麼?類是什麼?類被編譯成什麼,答案如下所示:
  • 組件指的是頁面的一部分,用類去實現,編譯成一個構造函數
  • 模塊是一個個webpack import引入的文件,ES6中的類在es5中就是構造函數
  1. 你是如何跟着社區成長的,答案如下所示:
  • 看英文官方文檔,去學習相應的原理
  1. 如何避免ajax數據重新獲取,答案如下所示:
  • 使用redux,判斷數據有沒有,有的話就不要再次請求
  1. react-router4的核心思想是什麼,和react-router3有什麼區別,答案如下所示:
  • react-router3的路由需要在一個文件內容易配置,而react-router4的理念則是把一個路由當做是一個組件,直接在組件中使用,這是react-router4react-router3在設計理念上的不同
  1. immutable.jsredux的最佳實踐,答案如下所示:
  • immutable來自於函數式編程的世界,我們可以稱它爲不可變,相等性檢查將包括兩個部分,值檢查和引用檢查
  • React重新渲染,React通過對組件屬性(props)和狀態(state)進行變更檢查以決定是否更新並重新渲染該組件,若組件狀態太過龐大,組件性能就會下降,因爲對象越複雜,其相等性檢查就會越慢。對於嵌套對象,必須迭代層層進行檢查判斷,耗費時間過長。若僅修改對象的屬性,其引用保持不變,相等性檢查中的引用檢查結果不變。Immutable提供一直簡單快捷的方式以判斷對象是否變更,對於React組件更新和重新渲染性能可以有較大幫助
  • Immutable數據,絕對不要突然修改對象,首先複製然後修改複製對象,再返回這個新對象,保持原對象不變。Immutable數據和原生JavaScript對象的主要差異爲持久化數據結構和結構共享,如下所示:
    • 持久數據結構,主張所有操作都返回該數據結構的更新副本,並保持原有結構不變,而不是改變原來的結構。通常利用 Trie 構建它不可變的持久性數據結構,它的整體結構可以看作一棵樹,一個樹節點可以對應代表對象某一個屬性,節點值即屬性值
    • 結構共享,一旦創建一個Immutable Trie型對象,我們可以把該Trie型對象想象成如下一棵樹,在之後的對象變更儘可能的重用樹節點。當我們要更新一個Immutable對象的屬性值時,就是對應着需要重構該Trie樹中的某一個節點,對於Trie樹,我們修改某一節點只需要重構該節點及受其影響的節點,即其祖先節點,如上圖中的四個綠色節點,而其他節點可以完全重用
  • React組件狀態必須是一個原生JavaScript對象,而不能是一個Immutable對象,因爲ReactsetState 方法期望接受一個對象然後使用 Object.assign 方法將其與之前的狀態對象合併,如下所示:
    • 使用Immutable.js的訪問API訪問state,如 get() , getIn()
    • 使用Immutable.js的集合操作生成組件子元素,使用高階函數如 map() , reduce() 等創React元素的子元素
    • 使用Immutable.js的更新操作API更新state
  • 對於 Immutable.jsRedux實踐,如下所示:
    • JavaScript對象轉換爲Immutable對象,如下所示:
      • 不要在Immutable對象中混用原生JavaScript對象
      • 當在Immutable對象內添加JavaScript對象時,首先使用 fromJS() 方法將JavaScript對象轉換爲Immutable對象,然後使用 update() , merge() , set() 等更新APIImmutable對象進行更新操作
    • Immutable與Redux state tree,如下所示:
      • 使用Immutable對象表示完整的Redux狀態樹,對於一個Redux應用,完整的狀態樹應該由一個Immutable對象表示,而沒有原生JavaScript對象
      • 使用 fromJS() 方法創建狀態樹,狀態樹對象可以是一個Immutable.Record或者任何其他的實現了 get , set , withMutations 方法的Immutable集合的實例
      • 使用redux-immutable庫調整 combineReducers 方法使其能處理Immutable
    • Immutable與Redux組件,如下所示:
      • 除了在展示型組件內,其他地方一律使用Immutable方式操作狀態對象。爲了保證應用性能,在容器組件,選擇器(selectors),reducer函數,action創建函數,sagasthunks函數內等所有地方均使用Immutable,但是不在展示型組件內使用
      • 在容器組件內使用Immutable,容器組件可以使用react-redux提供的 connect 方法訪問reduxstore,所以我們需要保證選擇器(selectors)總是返回Immutable對象,否則,將會導致不必要的重新渲染。另外,我們可以使用諸如reselect的第三方庫緩存選擇器(selectors)以提高部分情景下的性能
    • Immutable對象轉換爲JavaScript對象,如下所示:
      • 絕對不要在 mapStateToProps方法內使用 toJS() 方法,toJS() 方法每次會調用時都是返回一個原生JavaScript對象,如果在 mapStateToProps 方法內使用 toJS() 方法,則每次狀態樹(Immutable對象)變更時,無論該 toJS() 方法返回的JavaScript對象是否實際發生改變,組件都會認爲該對象發生變更,從而導致不必要的重新渲染
      • 絕對不要在展示型組件內使用 toJS() 方法,如果傳遞給某組件一個Immuatble對象類型的prop,則該組件的渲染取決於該Immutable對象,這將給組件的重用,測試和重構帶來更多困難
      • 當容器組件將Immutable類型的屬性(props)傳入展示型組件時,需使用高階組件(HOC)將其轉換爲原生JavaScript對象
  1. reselect是做什麼使用的,答案如下所示:
  • 充當vue裏面computed計算屬性的角
  • 如果依賴的數據沒有發生變化,計算屬性就不會重新計算,做緩存提升代碼性能
  • reselect的原理是,只要相關狀態不變,即直接使用上一次的緩存結果
  • reselect通過創建選擇器(selectors),該函數接受一個state參數,然後返回我們需要在 mapStateToProps 方法內返回對象的某一個數據項,一個選擇器的處理可以分爲兩個步驟,如下所示:
    • 接受state參數,根據我們提供的映射函數數組分別進行計算,如果返回結果和上次第一步的計算結果一致,說明命中緩存,則不進行第二步計算,直接返回上次第二步的計算結果,否則繼續第二步計算。第一步的結果比較,通常僅僅是 === 相等性檢查,性能是足夠的
    • 根據第一步返回的結果,計算,返回最終結果
  1. react-router基本原理,hashHistory,browserHistory,如下所示:
  • hashHistory: 不需要後端支持,hashHistory#
  • browserHistory:還需要後端在服務器上做配置
  1. 使用異步組件的情況,如下所示:
  • 異步組件,懶加載,按需加載
  • 如果可以,儘量在所有項目中使用,可以減小項目打包後的大小,在前端加載的時候,不會一次加載過大的js文件
  • Reloadable庫,路由懶加載,按需加載,訪問那個頁面加載哪個頁面代碼
  1. XSS攻擊在react中如何防範,如下所示:
  • react直接解析字符串,字符串帶有script標籤,標籤內寫有可執行的js代碼,
    儘量在創建的時候轉義
  • 代碼如下所示:
<div dangerouslySetInnerHTML={{ __html: '<script>alert(1)</script>' }}></div>
  1. getDerivedStateFromProps,getSnapshotBeforeUpdate,如下所示:
  • getDerivedStateFromProps和componentWillReceiveProps差不多,可以對state進行一些更改
  • getSnapshotBeforeUpdate和componentWillUpdate差不多,想要獲取更新之前的dom結構可以用它
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章