平時寫react 小技巧

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

    常常會遇處處理數組數據的狀況,能夠用下面的方式簡單的渲染出來。javascript

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

    好比 <input type="text" > 每次寫很麻煩吧,能夠封裝一個成一個組件css

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

    組件能夠分紅不少類類,有的是佈局類,有的是功能類。下面是一種佈局類的組件。html

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

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

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

    例子:node

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

    項目中常常會用到這兩種狀況如:
    受控組件,更新的時候須要使用this.setStatereact

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

    不受控組件,主要須要經過ref來獲取input的值。git

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

    兩種方法均可以在特定的場合去使用,我的以爲數據相對重要的頁面須要使用受控組件會比較合適。github

  • 使用三元表達式

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

    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)

相關文章
相關標籤/搜索