開發(fā)react須知

react官網(wǎng)教程基礎(chǔ)解析

1、使用redux和沒(méi)有redux,react寫法有什么不同嗎?

答:組件寫法一樣,但是state不一定交給組件內(nèi)部管理,可能放到store上統(tǒng)一管理。

2、認(rèn)識(shí)react,一個(gè)hello world!

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

3、如何使用react?

答:推薦你使用ES6語(yǔ)法來(lái)寫react,首先你需要Babel編譯你的ES6代碼,其次,你才可以使用比如 => (箭頭函數(shù)),class(類),模板文字,let和const語(yǔ)句等ES6語(yǔ)法。

4、JSX介紹

答:JSX是一種表達(dá)式,它有一個(gè)根標(biāo)簽,在內(nèi)部可以嵌入表達(dá)式,使用{}(大括號(hào))包裹起來(lái)。它看起來(lái)就是html的一部分,或者叫一個(gè)html模塊。

class T extends React.Component {
    render() {
        return <div className="left-enter" style={}>{value}</div>
    }
}

從上面的代碼例子你可以看到幾個(gè)和html不同的地方,class =》className,style是一個(gè)object,你還可以在dom元素中使用{}插入數(shù)據(jù)。

使用JSX還可以防止XSS(跨站腳本攻擊),因?yàn)镴SX只是表達(dá)式,它需要先轉(zhuǎn)換成字符串,然后才能渲染到真實(shí)DOM上面,但對(duì)于真正的黑客來(lái)說(shuō),這種做法也不是安全的。

4、元素和組件的概念

react組件:

class T extends React.Component {
    render() {
        return <div className="left-enter" style={}>{value}</div>
    }
}

react元素:

<div className="left-enter" style={}>{value}</div>

5、組件的使用

函數(shù)組件:函數(shù)組件沒(méi)有狀態(tài)和生命周期,但是你可以返回一個(gè)react元素。

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

class組件:非常強(qiáng)大,有自己的state和生命周期。和函數(shù)組件一樣,class組件也需要返回一個(gè)react元素。

class Welcome extends React.Component {
  componentWillMount() {}
  componentDidMount() {}
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

在一個(gè)龐大復(fù)雜的網(wǎng)站應(yīng)用中,要如何拆分組件呢?官網(wǎng)上說(shuō)組件拆分的越細(xì),復(fù)用性就越強(qiáng),從實(shí)際開發(fā)中來(lái)看,這個(gè)說(shuō)法沒(méi)有錯(cuò),但是
會(huì)帶來(lái)一個(gè)比較嚴(yán)重的問(wèn)題,就是組件太多,管理起來(lái)不方便。有人使用第三方react組件的時(shí)候,只有那些文檔非常強(qiáng)大的開源組件
才能給你的開發(fā)提高效率。如果你自己的組件也想拆分到細(xì)致,那么寫好文檔是最重要的一步。

react還提到了一點(diǎn),傳遞給組件的數(shù)據(jù)是"只讀"的,要保證組件中的數(shù)據(jù)是"純數(shù)據(jù)",輸入即輸出。那么,如果你需要在組件中修改props.data
該怎么做呢?

render() {
    const { data } = this.props
    //定義一個(gè)新的變量來(lái)保存修改后的值。
    let _data = data + 1;
}

6、組件的狀態(tài)和生命周期

前面我們提到組件分為函數(shù)組件和類組件,函數(shù)組件是無(wú)狀態(tài),類組件有狀態(tài)和生命周期。

什么是狀態(tài)?

答:通俗理解,就是組件不同時(shí)候的不同表現(xiàn),比如,一個(gè)按鈕組件,可能有激活狀態(tài),不可點(diǎn)擊狀態(tài),顯示狀態(tài),隱藏狀態(tài)等,在react用state來(lái)保存這些狀態(tài)。
而state本身不僅僅表示組件狀態(tài),還可以保存組件的數(shù)據(jù)。

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        isShow: true,
        text: props.text,
        disabled: true
    };
  }

  render() {
      const { isShow, text, disabled} = this.state
      return <button disabled={disabled} style={{display: isShow ? "block" : "none"}}>{text}</button>
  }
}

如果要修改state,請(qǐng)使用,注意,你不能在render函數(shù)里面直接修改state,而是要通過(guò)事件去觸發(fā)state更新。

this.setState({
    isShow: false,
    disabled: false
})

由于setState有批處理功能,所以該方法可能不一定同步更新,如果你需要依賴上一次的狀態(tài)和本次狀態(tài)的計(jì)算,那么需要寫成下面這種形式。

this.setState((prevState, props) => {    
      text: prevState.text++
    });

demo網(wǎng)址:http://codepen.io/hyy1115/pen/GmdOKJ?editors=0011

有時(shí)候,子組件不需要關(guān)注自身的狀態(tài),而是通過(guò)父組件的狀態(tài)來(lái)改變,這時(shí)候的子組件可以寫成函數(shù)形式,通過(guò)props傳遞父組件給的狀態(tài)。

react生命周期
生命周期表示組件的一生,從出生到輝煌到死亡,中間最主要也是最常用的3個(gè)狀態(tài)是:

componentWillMount:出生了,把組件的狀態(tài)和屬性都設(shè)置好。

componentDidMount:渲染出來(lái)了,我不再是JSX,而是真實(shí)DOM了。

componentWillUnmount:要死了,死之前把遺產(chǎn)處理好。

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        isShow: true,
        text: props.text,
        disabled: true
    };
  }
  
  componentWillMount() {
      //出生了,可以給我數(shù)據(jù)和設(shè)置我的狀態(tài)
  }
  componentDidMount() {
      //活著多好
  }
  componentWillUnmount() {
      //要死了,把我的一生痕跡都清除
  }

  render() {
      const { isShow, text, disabled} = this.state
      return <button disabled={disabled} style={{display: isShow ? "block" : "none"}}>{text}</button>
  }
}

還有其他幾個(gè)生命周期,并不是非常常用,需要用到的時(shí)候去看下別人的博客。

7、事件處理

 <button onClick={(e) => this.handleClick(e)}>
 按鈕
</button>

<input type="text" onChange={(e) => this.handleClick(e)} />

8、條件渲染

前面button的例子我們已經(jīng)使用到了條件渲染,條件渲染通過(guò)state來(lái)判斷,常用的是控制style、className、DOM屬性,JSX。

舉幾個(gè)常用的例子。

render() {
    return (
        <div>
        {
            this.state.isShow && <button>按鈕</button>    
        }
        </div>
    )
}
render() {
    return (
        <div>
        {
            this.state.isShow ? <button>按鈕</button> : <span>文本</span>
        }
        </div>
    )
}
render() {
    return <button disabled={this.state.disabled}>按鈕</button>
}

9、列表渲染

2個(gè)注意點(diǎn):

數(shù)組要判斷是否為空;

必須給一個(gè)key。

render() {
    const { arr } = this.state
    return arr.length > 0 && arr.map((value, key) => <li key={key}>{value}</li> )
}

10、表單

我曾經(jīng)經(jīng)歷過(guò)的一次阿里的面試,就考到了react表單的知識(shí)點(diǎn)。

受控組件:由react控制輸入的表單組件。

在下面的例子中,input的value值由state來(lái)決定,用戶輸入觸發(fā)onChange事件,然后更新state,達(dá)到修改value的目的。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  render() {
    return (
          <input type="text" value={this.state.value} onChange={this.handleChange} />
    );
  }
}

或許你沒(méi)看出來(lái)和正宗input元素的區(qū)別,看一個(gè)真實(shí)DOM元素的例子,value由inupt自身維護(hù),我們沒(méi)有給value綁定值。

<input type="text">

textarea和input是一樣的用法。

select有些許不同,將value綁定到select上,而不是option。

<select value={this.state.value} onChange={this.handleChange}>
    <option value="1">1</option>
    <option value="2">2</option>
</select>

還有一種是多個(gè)輸入框的情況,比如登錄,有賬號(hào)、密碼等,這時(shí)候操作這些不同的input可以通過(guò)ref或者name,class,id等方法去setState,看
官方demo。

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
      </form>
    );
  }
}

不受控組件:很簡(jiǎn)單,就是DOM自己維護(hù)狀態(tài)的組件,不受react控制。你可以給它設(shè)置defaultValue,但是不能去setState。

<input type="text" ref={(input) => this.input = input} defaultValue="默認(rèn)值"/>

相信有人會(huì)試過(guò)設(shè)置defaultValue之后執(zhí)行了setState去修改value,這樣做控制臺(tái)會(huì)發(fā)出警告。

總結(jié):受控組件是指受react控制的組件,表單組件中的value和state同步,不受控組件是指不受react控制的組件,表單組件中的
value不通過(guò)state同步,只能操作DOM去讀取value。

11、狀態(tài)提升

你一定聽說(shuō)過(guò)變量提升,函數(shù)提升,那么狀態(tài)提升是什么呢?

首先你得了解雙向綁定和單向數(shù)據(jù)流,雙向綁定中,數(shù)據(jù)可以在不同的組件之間實(shí)現(xiàn)共享,這樣做的確有很大的好處,但是在react中,
不推薦使用雙向綁定,而是使用狀態(tài)提升的方式。

記得和阿里的一個(gè)面試官聊的時(shí)候,他要求我用react實(shí)現(xiàn)雙向綁定,而我認(rèn)為react應(yīng)該采用狀態(tài)提升來(lái)實(shí)現(xiàn)。最后沒(méi)說(shuō)服他,或許讓Dan來(lái)
和他聊聊才有用,哈哈。

狀態(tài)提升:state推崇單向數(shù)據(jù)流,數(shù)據(jù)從父組件通過(guò)props流向子組件,如果你在子組件中,需要修改state來(lái)和其他子組件共享數(shù)據(jù)更新,
你需要使用回調(diào)函數(shù)給使數(shù)據(jù)更新給父組件,然后從父組件流向其他的子組件,這樣做是保證數(shù)據(jù)有單一的來(lái)源。

如果實(shí)子組件和子組件之間任意共享數(shù)據(jù),那么,后期維護(hù)會(huì)比較痛苦,特別是找bug的時(shí)候。

看一個(gè)狀態(tài)提升的例子吧。


class Child extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.upDateValue(e.target.value);
  }

  render() {
    const {name, value} = this.props;
    return (
      <div>
        <p>{name}:</p>
        <input value={value}
               onChange={this.handleChange} 
          />
      </div>
    );
  }
}

class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: '', name: ''};
    
    this.upDateValue = this.upDateValue.bind(this);
  }

  upDateValue(value) {
    this.setState({value: value})
  }
  
  render() {
    const {value} = this.state;

    return (
      <div>
        <Child name="組件1" value={value} upDateValue={this.upDateValue} />
        <Child name="組件2" value={value} upDateValue={this.upDateValue} />
      </div>
    );
  }
}

ReactDOM.render(
  <Demo />,
  document.getElementById('root')
);

demo網(wǎng)址:http://codepen.io/hyy1115/pen/xdjoZQ?editors=0011

12、選擇組合還是繼承?

用過(guò)原生js或者jQuery的同學(xué)可能對(duì)基礎(chǔ)非常熟悉,繼承可以實(shí)現(xiàn)擴(kuò)展很多功能。

在react組件開發(fā)中,我們的每個(gè)react組件都是繼承于React.Component。

class MyComponent extends React.Component {
    
}

我們不推薦你繼承MyComponent。

//不推薦
class NextComponent extends MyComponent {
    
}

你應(yīng)該充分利用react組件的強(qiáng)大性能,開發(fā)各種你需要的組件繼承至React.Component。組件之間的嵌套非常強(qiáng)大,你可以嵌套函數(shù)組件,嵌套類組件。

詳情前往:https://facebook.github.io/react/docs/composition-vs-inheritance.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評(píng)論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評(píng)論 2 374