平時寫react 小技巧


  • Stateless function 無狀態組件平時寫組件用到比較多的就是無狀態組件,不但優雅,也是優化react性能的一種手段。
      const Greeting = ({ name, style }) => { return <div style={style}>{name}</div> };
  • Array as children 把數組數據渲染出來

    經常會遇到處理數組數據的情況,可以用下面的方式簡單的渲染出來。

      render() {
          return ( (<ul> {List.map((item) => ( <li>{item}</li> ))} </ul>) ) }
  • 封裝基礎類組件

    比如 <input type="text" > 每次寫很麻煩吧,可以封裝一個成一個組件

      const input = (props) => { return <input type = {props.type} {...props} /> }
  • Layout Component 布局組件

    組件可以分成很多類類,有的是布局類,有的是功能類。下面是一種布局類的組件。

      <FlexContainer> <div style={{ flex: 1 }}>{this.props.leftSide}</div> <div style={{ flex: 2 }}>{this.props.rightSide}</div> </FlexContainer>
  • Higher Order Component 高階組件

    高階組件很像decorator,提升組件的能力。比如你想一些組件里面使用一下功能,react-router 中

      import { withRouter } from 'react-router' withRouter(SomeComponent)

    例子:

      var Enhance = ComposedComponent => class extends React.Component { componentDidMount() { this.setState({ name: "李狗子" }); } render() { return <ComposedComponent {...this.props} name = {this.state.name} />; } };
  • 受控組件,不受控組件

    項目中經常會用到這兩種情況如:
    受控組件,更新的時候需要使用this.setState

      constructor() { super(); this.state = {value: ""} } render() { return <input type="text" value={this.state.value} /> }

    不受控組件,主要需要通過ref來獲取input的值。

      render() { return <input type="text" ref="myInput" /> }

    兩種方法都可以在特定的場合去使用,個人覺得數據相對重要的頁面需要使用受控組件會比較合適。

  • 使用三元表達式

    項目中經常有判斷語句,用三元表達式可以很方便的寫出想要的邏輯

      const demo = ({ isOK }) => { return isOK ? <p> Yes </p> : <p> No </p> };
  • 給setState傳入function

    可以使用function來更新state

      this.setState((prevState, props) => ({ return ... }));
  • 通過ref屬性獲取component

    場景:下面的例子是初始化組件后,讓input默認獲取光標。ref最終指向的已經渲染好的DOM節點,或者是react class的實例。具體可以看官方的文檔

      componentDidMount() {
          this.input.focus(); } render() { return ( <input ref={comp => { this.input = comp; }} /> ) }
  • 切勿使用...props傳遞數據

    一個非常錯誤的做法比如:

      <Component {...props} />

    props上面如果有非常多的屬性,會造成非常昂貴的計算。正確的應該

      <Component name = { props.name } />

以上是平時寫React用到的一些寫法小技巧,說有用還蠻有用的!

有錯誤的地方還請指正!謝謝大家。

下面2個鏈接都很棒哦!記得收藏star...

參考:

https://github.com/vasanthk/react-bits

react 代碼規范

https://github.com/airbnb/javascript/tree/master/react

 

 

dangerouslySetHTML 和 style 屬性

 

dangerouslySetHTML

出於安全考慮的原因(XSS 攻擊),在 React.js 當中所有的表達式插入的內容都會被自動轉義,就相當於 jQuery 里面的 text(…) 函數一樣,任何的 HTML 格式都會被轉義掉:

class Editor extends Component { constructor() { super() this.state = { content: '<h1>React.js 小書</h1>' } } render () { return ( <div className='editor-wrapper'> {this.state.content} </div> ) } } 

假設上面是一個富文本編輯器組件,富文本編輯器的內容是動態的 HTML 內容,用 this.state.content 來保存。我希望在編輯器內部顯示這個動態 HTML 結構,但是因為 React.js 的轉義特性,頁面上會顯示:

表達式插入並不會把一個 <h1> 渲染到頁面,而是把它的文本形式渲染了。那要怎么才能做到設置動態 HTML 結構的效果呢?React.js 提供了一個屬性 dangerouslySetInnerHTML,可以讓我們設置動態設置元素的 innerHTML:

...
  render () {
    return ( <div className='editor-wrapper' dangerouslySetInnerHTML={{__html: this.state.content}} /> ) } ... 

需要給 dangerouslySetInnerHTML 傳入一個對象,這個對象的 __html 屬性值就相當於元素的 innerHTML,這樣我們就可以動態渲染元素的 innerHTML 結構了。

有寫朋友會覺得很奇怪,為什么要把一件這么簡單的事情搞得這么復雜,名字又長,還要傳入一個奇怪的對象。那是因為設置 innerHTML 可能會導致跨站腳本攻擊(XSS),所以 React.js 團隊認為把事情搞復雜可以防止(警示)大家濫用這個屬性。這個屬性不必要的情況就不要使用。

style

React.js 中的元素的 style 屬性的用法和 DOM 里面的 style 不大一樣,普通的 HTML 中的:

<h1 style='font-size: 12px; color: red;'>React.js 小書</h1> 

在 React.js 中你需要把 CSS 屬性變成一個對象再傳給元素:

<h1 style={{fontSize: '12px', color: 'red'}}>React.js 小書</h1> 

style 接受一個對象,這個對象里面是這個元素的 CSS 屬性鍵值對,原來 CSS 屬性中帶 - 的元素都必須要去掉 - 換成駝峰命名,如 font-size 換成 fontSizetext-align 換成 textAlign

用對象作為 style 方便我們動態設置元素的樣式。我們可以用 props 或者 state中的數據生成樣式對象再傳給元素,然后用 setState 就可以修改樣式,非常靈活:

<h1 style={{fontSize: '12px', color: this.state.color}}>React.js 小書</h1> 

只要簡單地 setState({color: 'blue'}) 就可以修改元素的顏色成藍色。

 

 

 

 

Prop 驗證

隨着應用不斷變大,保證組件被正確使用變得非常有用。為此我們引入propTypesReact.PropTypes 提供很多驗證器 (validator) 來驗證傳入數據的有效性。當向 props 傳入無效數據時,JavaScript 控制台會拋出警告。注意為了性能考慮,只在開發環境驗證 propTypes。下面用例子來說明不同驗證器的區別:

React.createClass({ propTypes: { // 可以聲明 prop 為指定的 JS 基本類型。默認 // 情況下,這些 prop 都是可傳可不傳的。 optionalArray: React.PropTypes.array, optionalBool: React.PropTypes.bool, optionalFunc: React.PropTypes.func, optionalNumber: React.PropTypes.number, optionalObject: React.PropTypes.object, optionalString: React.PropTypes.string, // 所有可以被渲染的對象:數字, // 字符串,DOM 元素或包含這些類型的數組。 optionalNode: React.PropTypes.node, // React 元素 optionalElement: React.PropTypes.element, // 用 JS 的 instanceof 操作符聲明 prop 為類的實例。 optionalMessage: React.PropTypes.instanceOf(Message), // 用 enum 來限制 prop 只接受指定的值。 optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), // 指定的多個對象類型中的一個 optionalUnion: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, React.PropTypes.instanceOf(Message) ]), // 指定類型組成的數組 optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), // 指定類型的屬性構成的對象 optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), // 特定形狀參數的對象 optionalObjectWithShape: React.PropTypes.shape({ color: React.PropTypes.string, fontSize: React.PropTypes.number }), // 以后任意類型加上 `isRequired` 來使 prop 不可空。 requiredFunc: React.PropTypes.func.isRequired, // 不可空的任意類型 requiredAny: React.PropTypes.any.isRequired, // 自定義驗證器。如果驗證失敗需要返回一個 Error 對象。不要直接 // 使用 `console.warn` 或拋異常,因為這樣 `oneOfType` 會失效。 customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error('Validation failed!'); } } }, /* ... */ }); 
  static get propTypes () {     return {       todoLeft: PropTypes.number.isRequired,       actions: PropTypes.object.isRequired,       filter: PropTypes.string.isRequired     }   } ...   <strong>{this.props.todoLeft}</strong> ...

 

默認 Prop 值

React 支持以聲明式的方式來定義 props 的默認值。

var ComponentWithDefaultProps = React.createClass({ getDefaultProps: function() { return { value: 'default value' }; } /* ... */ }); 

當父級沒有傳入 props 時,getDefaultProps() 可以保證 this.props.value 有默認值,注意 getDefaultProps 的結果會被 緩存。得益於此,你可以直接使用 props,而不必寫手動編寫一些重復或無意義的代碼。

傳遞 Props:小技巧

有一些常用的 React 組件只是對 HTML 做簡單擴展。通常,你想少寫點代碼來把傳入組件的 props 復制到對應的 HTML 元素上。這時 JSX 的 spread 語法會幫到你:

var CheckLink = React.createClass({ render: function() { // 這樣會把 CheckList 所有的 props 復制到 <a> return <a {...this.props}>{'√ '}{this.props.children}</a>; } }); React.render( <CheckLink href="/checked.html"> Click here! </CheckLink>, document.getElementById('example') ); 

單個子級

React.PropTypes.element 可以限定只能有一個子級傳入。

var MyComponent = React.createClass({ propTypes: { children: React.PropTypes.element.isRequired }, render: function() { return ( <div> {this.props.children} // 有且僅有一個元素,否則會拋異常。 </div> ); } }); 

Mixins

組件是 React 里復用代碼最佳方式,但是有時一些復雜的組件間也需要共用一些功能。有時會被稱為 跨切面關注點。React 使用 mixins 來解決這類問題。

一個通用的場景是:一個組件需要定期更新。用 setInterval() 做很容易,但當不需要它的時候取消定時器來節省內存是非常重要的。React 提供 生命周期方法 來告知組件創建或銷毀的時間。下面來做一個簡單的 mixin,使用 setInterval() 並保證在組件銷毀時清理定時器。

var SetIntervalMixin = { componentWillMount: function() { this.intervals = []; }, setInterval: function() { this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { this.intervals.map(clearInterval); } }; var TickTock = React.createClass({ mixins: [SetIntervalMixin], // 引用 mixin getInitialState: function() { return {seconds: 0}; }, componentDidMount: function() { this.setInterval(this.tick, 1000); // 調用 mixin 的方法 }, tick: function() { this.setState({seconds: this.state.seconds + 1}); }, render: function() { return ( <p> React has been running for {this.state.seconds} seconds. </p> ); } }); React.render( <TickTock />, document.getElementById('example') );

關於 mixin 值得一提的優點是,如果一個組件使用了多個 mixin,並且有多個 mixin 定義了同樣的生命周期方法(如:多個 mixin 都需要在組件銷毀時做資源清理操作),所有這些生命周期方法都保證會被執行到。方法執行順序是:首先按 mixin 引入順序執行 mixin 里方法,最后執行組件內定義的方法。

 

 

 

 

 

這篇文章主要是寫關於學習react中的一些自己的思考:

 

1.setState到底是同步的還是異步的?

2.如何在子組件中改變父組件的state

3.context的運用,避免“props傳遞地獄”

4.組件類里有私有變量a,它到底改放在this.a中還是this.state對象中(作為屬性a)呢?

 

1.setState到底是同步的還是異步的?

class MyComponent extends React.Component{ constructor(props) { super(props)  this.state ={ value:0 } } handleClick = () => {  this.setState({value:1}) console.log('在handleClick里輸出' + this.state.value); } render(){ console.log('在render()里輸出' + this.state.value); return (<div> <button onClick ={this.handleClick}>按鈕</button> </div>)  } } export default MyComponent
//省略渲染過程,下面也一樣

 

在這里我們點擊按鈕時,調用handleClick函數,首先調用this.setState()設置value,隨即把this.state.value輸出,結果是什么?

你可能會想,這還不簡單——“在handleClick里輸出1”唄,然而你錯了,它的結果為:

 

事實上,setState()的調用是異步的,這意味着,雖然你調用了setState({value:0}),但this.state.value並不會馬上變成0,而是直到render()函數調用時,setState()才真正被執行。結合圖說明一下:

 

你可能又會問了:要是我在render()前多次調用this.setState()改變同一個值呢?(比如value)

 

我們對handleClick做一些修改,讓它變得復雜一點,在調用handleClick的時候,依次調用handleStateChange1 ,handleStateChange2,handleStateChange3,它們會調用setState分別設置value為1,2,3並且隨即打印

handleStateChange1 = () => {  this.setState({value:1}) console.log('在handleClick里輸出' + this.state.value); } handleStateChange2 = () => {  this.setState({value:2}) console.log('在handleClick里輸出' + this.state.value); } handleStateChange3 = () => {  this.setState({value:3}) console.log('在handleClick里輸出' + this.state.value); } handleClick = () => {  this.handleStateChange1();  this.handleStateChange2();  this.handleStateChange3(); }

 

那么輸出結果會是什么呢?如果setState是同步調用的,那么結果顯然為

在handleClick里輸出1

在handleClick里輸出2

在handleClick里輸出3

 

但是結果為:,證明它是異步的

 

這下好理解了吧,配合這幅圖:

2.如何在子組件中改變父組件的state呢?

這是我們經常會遇到的問題之一,解決辦法是:在父組件中寫一個能改變父組件state的方法,並通過props傳入子組件中

class Son extends React.Component{ render(){  return(<div onClick = {this.props.handleClick}> {this.props.value}  </div>)  } } class Father extends React.Component{ constructor(props){ super(props)  this.state ={ value:'a' } } handleClick = () => {  this.setState({value:'b'}) } render(){  return (<div style ={{margin:50}}> <Son value = {this.state.value} handleClick = {this.handleClick}/> </div>)  } }

 

點擊子組件Son,內容由a變成b,說明父組件的state被修改了

3.context的運用,避免“props傳遞地獄”

 

3.1假設一個比較極端的場景:你需要從你的子組件里調用父父父父父組件的屬性或方法,怎么辦!當組件嵌套層級過深的時候,不斷地傳props作為實現方式簡直就是噩夢!我稱之為“props傳遞地獄”(這個詞是我瞎編的,參考自“回調函數地獄”)

 

我們接下來實現的是這樣一個需求,把gene屬性(基因)從組件GrandFather -->Father --> Son傳遞,如果用props傳遞:

class Son extends React.Component{ render(){  return (<h3 style ={{marginTop:30}}>我從我的爺爺那里得到了基因--{this.props.gene}</h3>)  } } class Father extends React.Component{ render(){  return (<Son gene = {this.props.gene}/>)  } } class GrandFather extends React.Component{ constructor(props) { super(props)  this.state ={ gene:'[爺爺的基因]' } } render(){  return (<Father gene = {this.state.gene}/>)  } }

demo:

 

【(。・`ω´・)雖然聽起來有點怪怪的但是大家別介意哈】

 

實現是實現了,但你想想,假設不是從“爺爺”組件,而是從“太太太太爺爺”組件傳下來,這多可怕!不過沒關系,react提供了一個叫做context(上下文)的API,你在頂層組件的context中定義的屬性,可以在所有的后代組件中,通過this.context.屬性去引用!讓我們一睹為快:

class Son extends React.Component{ render(){ console.log(this.context.color);  return (<h3 style ={{marginTop:30}}>我從我的爺爺那里得到了基因--{this.context.gene}</h3>)  } } Son.contextTypes ={ gene:React.PropTypes.string } class Father extends React.Component{ render(){  return (<Son/>)  } } class GrandFather extends React.Component{ getChildContext(){  return {gene:'[爺爺的基因]'} } render(){  return (<Father />)  } } GrandFather.childContextTypes = { gene: React.PropTypes.string }; export default GrandFather

demo效果同上!這個時候你發現,我們在<GrandFather>組件和<Father>組件中都沒有向下傳遞props,我們就從最下層的Son組件中獲取了gene屬性,是不是很方便!

 

解釋下代碼:

getChildContext()是你在頂層組件中定義的鈎子函數,這個函數返回一個對象——你希望在后代組件中取用的屬性就放在這個對象中,譬如這個例子中我希望在Son組件中通過this.context.gene取屬性,所以在getChildContext()中返回{gene:'[爺爺的基因]'}

GrandFather.childContextTypes和Son.contextTypes 用於規定頂層組件和取頂層組件context的后代組件的屬性類型

 

【注意】GrandFather.childContextTypes和Son.contextTypes 這兩個對象必須要規定!否則context只能取到空對象!一開始我犯的這個錯誤簡直讓我狂吐三升血。。。。

 

有圖有真相之context和props的區別

 

3.2context是否推薦使用?

雖然上面這個例子說明了context多么好用,但注意:官方並不推薦經常使用它,因為它會讓你的應用架構變得不穩定(官方文檔原話If you want your application to be stable, don't use context),在我看來,為什么在大多數情況下要使用props而不是實現數據流呢,因為props憑借組件和組件間嚴密的邏輯聯系,使得你能夠清晰地跟蹤應用的數據流(it's easy to track the flow of data through your React components with props)當然了,如果你遇到上述的例子的情況,context還是大有裨益的 

3.3需要改變context中的屬性時候,不要直接改變它,而是使用this.state作為媒介,如果你試圖在頂層組件的state中放入一個可變的屬性你可以這樣做:

getChildContext(){ return {type:this.state.type} }

 

3.4在上述我限制gene的類型時候我是這樣寫的:gene: React.PropTypes.string,使用了React內置的React.PropTypes幫助屬性,此時我的版本為 "react": "15.4.2",在15.5的版本后這一幫助屬性被廢棄,推薦使用props-types庫,像這樣:

const PropTypes = require("Prop-Types"); GrandFather.childContextTypes = { gene: PropTypes.string };

 

當然,在這之前你需要npm install prop-types

 

4組件類里有私有變量a,它到底改放在this.a中還是this.state對象中(作為屬性a)呢?

這得根據它是否需要實時的重渲染決定,如果該變量需要同步到變化的UI中,你應該把它放在this.state對象中,如果不需要的話,則把它放在this中(無代碼無demo)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM