React 中, 在 Controlled
(受控制)的文本框中輸入中文 onChange
會觸發多次
通過輸入法輸入中文,日文,不管哪種一種用拼音的、筆划的,只要按下鍵盤的動作都會觸發文本框的 change
事件。 但是 React
中的受控組件都通過觸發 change
事件后得到的值再去更新組件的value
, 這樣不停的觸發 change
,導致 value
一直在更新,組件就一直在 render, 可能會造成組件運行邏輯問題,輸入框內出現很多字符,而且中文輸入不進去。
在 DOM events 中另外有 3 個事件可以輔助監聽一段文字的輸入:
- compositionstart : 事件觸發於一段文字的輸入之前;
- compositionupdate : 事件觸發於字符被輸入到一段文字的時候;
- compositionend : 事件觸發於一段文字的輸入完成。
我們可以通過這 3 個事件判斷當前輸入是否完整的輸入,再觸發 onChange
事件,這樣就能解決多次觸發 onChange
的問題。 還有一個重要的問題,雖然 onChange
要等一次完整輸入后才觸發,但是文本框上的顯示需要是實時的,所以還要考慮在 state
中維護一個 innerValue
做實時更新,這樣就沒有問題了。
另外這 3 個事件在各個瀏覽器上的兼容性不一樣,所以還要考慮兼容性的問題。 具體詳細的實現可以參考 form-lib。
Warning: It looks like you’re using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster.
當 React 升級到 v15.* 以后,可能會見到這個警告,它是意思說你在生產環境中使用的是一個開發環境 minified 的代碼。
那 React 它是怎么辦判斷你正在訪問的是生產環境,而不是開發環境呢? 它是通過 webpack 知道的,因為最終發布生產環境的代碼都是通過 webpack 命令打包。如果你是在開發環境,那肯定是用 webpack-dev-server。 在生產環境中不應該包括開發中使用的所有額外代碼,所以在 webpack 部署環境中需要添加以下配置:
1 |
module.exports = { |
參考Make your own React production version with webpack
setState(…): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.
這個警告是說,在一個已經卸載的組件上調用 setState
是無效的。出現這種情況一般都是異步操作造成的,比如一個異步數據請求,響應后執行 setState
去更新組件,但是如果在異步請求未完成前,路由發生變化,頁面當前組件被卸載,這個時候異步請求沒有被中止,導致等請求完成后就會執行 setState
試圖去更新組件,就會報當前錯誤。
解決辦法很簡單,一般都是在執行 setState
之前判斷一下當前組件是否被卸載,如果沒有被卸載,才執行 setState
。在 ES6 以前可以通過 this.isMounted()
來判斷當前組件是否裝載,如下:
1 |
if(this.isMounted()) { // This is bad. |
但是在 ES6 以后不能用這種方式,這是一種反模式,參考isMounted is an Antipattern
可以利用組件的生命周期自己維護一個 isMounted
狀態, 在 componentDidMount
中把 isMounted
設置為 true
,
在 componentWillUnmount
再將 isMounted
設置為 false
。 通過 isMounted
變量來判斷組件是否裝載。
Each child in an array or iterator should have a unique key
prop.
這個警告很明確,在遍歷子元素的時候,每一個子元素都應該有一個唯一的 key
。
參考官網相關說明 lists and keys
但是這里需要注意,避免使用數組的 index 來作為屬性 key 的值,推薦使用唯一 ID。
參考 Index as a key is an anti-pattern
1 |
const todoItems = todos.map((todo) => |
在 IE 11 控制台報錯:Objects are not valid as a React child
錯誤的全文: error-decoder
這問題一般會在開發環境中遇到,在使用 React 15.4 以后,如果使用了 react-hot-loader
則必須在熱加載之前加載 babel-polyfill
, 在你的 webpack.config.js
中參考如下配置:
1 |
entry: [ |
在 IE 11 控制台報錯:Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.
如果出現這個錯誤是提示,在本地環境配置 NODE_ENV=development
,再看一下控制台是否輸出了一些更詳細的錯誤信息,參考 Introducing React’s Error Code System 。
如果這個錯誤只在 IE 11 瀏覽器環境出現,一般都是 ES6+ 的語法在IE存在兼容問題,一個比較通用的解決辦法就是在項目中引入一個 babel-polyfill
1 |
npm i —save babel-polyfill |
在項目入口,引入 babel-polyfill
1 |
import 'babel-polyfill' |
在 webpack 構建的時候會兼容性處理
在 IE 11 控制台報錯: Promise is undefined
IE 11 不支持 Promise 對象,解決辦法
1 |
npm i —save es6-promise |
在項目入口,引入es6-promise
1 |
import 'es6-promise/auto'; |
在 IE 11 瀏覽器上 FontIcon 圖標不顯示
這個問題和 React 沒有關系,但是這里也記錄一下。
在 IE11 會下載 .ttf/.woff 字體文件, 通過 Network 我們可以看到字體文件 response headers
中有一個 Pragma:no-cache
,由於 IE 似乎有緩存和字體的問題,所有導致圖標不能正常顯示。所以刪除 WEB 服務(Nginx..)中的 Pragma:no-cache
和 Cache-Control:no-store
就能正常訪問。
在 React 中使用 debounce
如果需要在 React 組件中使用 debounce 方法可以參考下面代碼
1 |
class SearchBox extends React.Component { |
因為 React
中 SyntheticEvent
是共用的,也就是說 SyntheticEvent
對象將會循環使用。而每次執行完事件后,它所有的屬性都將會失效(所有屬性的值都被置為了 null
)。所以在調用 debounce
方法前,一定要先調用 e.persist()
來移除 SyntheticEvent
,並允許 event
對象被保留下來以用於你自己的代碼。
參考文章: