React深入(一)

Context

使用場景

  1. 為了解決props的繁瑣傳遞問題家夺,Context提供一種組件間共享值的方式鞭缭,不必顯示通過組件數(shù)逐層傳遞props;
  2. 很多不同層級的組件需要訪問同樣一些的數(shù)據(jù)躺盛,例如獲取當前認證的用戶把沼、主題或首選語言古戴,類似于全局緩存劲赠;
  3. Context有時候可由組件組合(component composition鼠证,即把組件當做props傳遞)代替峡竣。

使用步驟

  1. 創(chuàng)建context:
    const ThemeContext = React.createContext({theme: 'light', text: '按鈕'});
    ThemedButton.contextType = ThemeContext;

  2. 賦值context:
    <ThemeContext.Provider value={{theme: 'primary', text: '提交'}}>
    這里的value值可以傳字符串,數(shù)字或者對象量九;
    如要更新context适掰,可以通過更新state再把state傳入context的方式實現(xiàn)。

  3. 渲染context:
    static contextType = ThemeContext;
    // React 會往上找到最近的 theme Provider荠列,然后使用它的值类浪。
    return <div className={'btn '+this.props.theme}>{this.props.value}</div>

    <ThemeContext.Consumer>
    {
    context => (
    <div className={'btn '+this.context.theme}>{this.context.text}</div>
    )
    }
    </ThemeContext.Consumer>

  4. context嵌套:
    <ThemeContext.Provider value={theme}>
    <UserContext.Provider value={signedInUser}>
    <Layout />
    </UserContext.Provider>
    </ThemeContext.Provider>

    // 一個組件可能會消費多個 context
    function Content() {
    return (
    <ThemeContext.Consumer>
    {theme => (
    <UserContext.Consumer>
    {user => (
    <ProfilePage user={user} theme={theme} />
    )}
    </UserContext.Consumer>
    )}
    </ThemeContext.Consumer>
    );

Refs轉(zhuǎn)發(fā)

使用場景

  1. 需要將 ref 自動地通過組件傳遞到其一子組件;
  2. 父組件通過React.createRef()生成傳入肌似,子組件通過React.forwardRef((props, ref) => ())接收渲染费就。

Fragments

  1. 一個組件返回多個元素。Fragments 允許你將子列表分組川队,而無需向 DOM 添加額外節(jié)點力细,
    如return (
    <React.Fragment>
    <ChildA />
    <ChildB />
    <ChildC />
    </React.Fragment>
    );
  2. 循環(huán)時key可以加在React.Fragment節(jié)點標簽上。

高階組件(HOC)

  1. 高階組件是參數(shù)為組件固额,返回值為新組件的函數(shù)眠蚂。

  2. 使用方法:
    class ShowUserPermit extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    return (
    <div>showUserPermit... {this.props.VIP}</div>
    )
    }
    }
    class ShowUserVipInfo extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    return (
    <div>showUserVipInfo... {this.props.VIP}</div>
    )
    }
    }

    function wrap(WrappedComponent) {
    return class reComponent extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    VIP: 1000
    }
    }
    render() {
    return <WrappedComponent VIP={this.state.VIP}/>
    }
    }
    }

    const id = document.getElementById('example');
    const OtherShowUserVipInfo = wrap(ShowUserVipInfo);
    const OtherShowUserPermit = wrap(ShowUserVipInfo);
    const ele = <React.Fragment>
    <OtherShowUserVipInfo />
    <OtherShowUserPermit />
    </React.Fragment>
    ReactDOM.render(ele, id);

  3. HOC 不會修改傳入的組件,也不會使用繼承來復(fù)制其行為对雪。相反河狐,HOC 通過將組件包裝在容器組件中來組成新組件。HOC 是純函數(shù)瑟捣,沒有副作用馋艺;

  4. 不要在 render 方法中使用 HOC;

深入JSX

  1. 在 JSX 類型中使用點語法:
    const MyComponents = {
    DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
    }
    }

    function BlueDatePicker() {
    return <MyComponents.DatePicker color="blue" />;
    }

  2. 用戶定義的組件必須以大寫字母開頭;

  3. 在運行時選擇類型:
    function Story(props) {
    // 錯誤!JSX 類型不能是一個表達式迈套。
    return <components[props.storyType] story={props.story} />;
    }
    function Story(props) {
    // 正確捐祠!JSX 類型可以是大寫字母開頭的變量。
    const SpecificStory = components[props.storyType];
    return <SpecificStory story={props.story} />;
    }

  4. JavaScript 表達式可作為 Props桑李,如<MyComponent foo={1 + 2 + 3 + 4} />;

  5. if 語句以及 for 循環(huán)不是 JavaScript 表達式踱蛀,所以不能在 JSX 中直接使用窿给,但是可以在JSX之外用;

  6. Props 默認值為 True

  7. props展開:
    const props = {firstName: 'Ben', lastName: 'Hector'};
    <Hello {...props}/> 與 <Hello firstName={props.firstName} lastName={props.lastName} />等價

  8. 如果你想渲染 false、true率拒、null崩泡、undefined 等值,你需要先將它們轉(zhuǎn)換為字符串:
    <div>My JavaScript variable is {String(myVariable)}.</div>

Portals

ReactDOM.createPortal(child, container)

  1. Portal 提供了一種將子節(jié)點渲染到存在于父組件以外的 DOM 節(jié)點的優(yōu)秀的方案;
  2. 第一個參數(shù)(child)是任何可渲染的 React 子元素猬膨,例如一個元素角撞,字符串或 fragment。第二個參數(shù)(container)是一個 DOM 元素勃痴。

Render Props

  1. 在 React 組件之間使用一個值為函數(shù)的 prop 共享代碼的簡單技術(shù);
  2. 具有 render prop 的組件接受一個返回 React 元素的函數(shù)谒所,并在組件內(nèi)部通過調(diào)用此函數(shù)來實現(xiàn)自己的渲染邏輯:
    <DataProvider render={data => (<h1>{data.target}</h1>)}/>
  3. 本質(zhì)上是把一個回調(diào)函數(shù)傳入到組件里,通過回調(diào)函數(shù)的參數(shù)data再次渲染指定組件沛申;
  4. 任何被用于告知組件需要渲染什么內(nèi)容的函數(shù) prop 在技術(shù)上都可以被稱為 “render prop”劣领,不一定非要起 render 名稱;
  5. 實例代碼如下:
    // 以下組件跟蹤 Web 應(yīng)用程序中的鼠標位置
    class Man extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    const mouse = this.props.mouse;
    return <p>人散步:當前的人的位置是 ({mouse.x}, {mouse.y})</p>
    }
    }
    class Cat extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    const mouse = this.props.mouse;
    return <p>貓追老鼠:當前的貓的位置是 ({mouse.x}, {mouse.y})</p>
    }
    }
    class Mouse extends React.Component {
    constructor (props) {
    super(props);
    this.state = {
    x: 0,
    y: 0
    };
    this.handleMouseMove = this.handleMouseMove.bind(this);
    }
    handleMouseMove(event) {
    this.setState({
    x: event.clientX,
    y: event.clientY
    });
    }
    render() {
    return (
    <div style={{height: '10vh'}} onMouseMove={this.handleMouseMove}>
    { /<Cat mouse={this.state}/>/ }
    {
    /*
    使用 renderprop 動態(tài)決定要渲染的內(nèi)容,
    而不是給出一個 <Mouse> 渲染結(jié)果的靜態(tài)表示
    b
    */
    }
    {
    this.props.render(this.state,this.props.type)
    }
    </div>
    )
    }
    }
    class MouseTracker extends React.Component {
    constructor(props) {
    super(props);
    this.renderMouse = this.renderMouse.bind(this);
    }
    renderMouse(mouse,Type) {
    return <Type mouse={mouse}/>
    }
    render() {
    return (
    <div>
    <h1>移動鼠標!</h1>
    <Mouse type={Cat} render={this.renderMouse}/>
    <Mouse type={Man} render={this.renderMouse}/>
    </div>
    )
    }
    }
    const id = document.getElementById('example');
    const ele = <React.Fragment>
    <MouseTracker />
    </React.Fragment>;
    ReactDOM.render(ele, id);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铁材,一起剝皮案震驚了整個濱河市尖淘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衫贬,老刑警劉巖德澈,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異固惯,居然都是意外死亡梆造,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門葬毫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镇辉,“玉大人,你說我怎么就攤上這事贴捡『龈兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵烂斋,是天一觀的道長屹逛。 經(jīng)常有香客問我,道長汛骂,這世上最難降的妖魔是什么罕模? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮帘瞭,結(jié)果婚禮上淑掌,老公的妹妹穿的比我還像新娘。我一直安慰自己蝶念,他們只是感情好抛腕,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布芋绸。 她就那樣靜靜地躺著,像睡著了一般担敌。 火紅的嫁衣襯著肌膚如雪摔敛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天柄错,我揣著相機與錄音舷夺,去河邊找鬼。 笑死售貌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的疫萤。 我是一名探鬼主播颂跨,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扯饶!你這毒婦竟也來了恒削?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尾序,失蹤者是張志新(化名)和其女友劉穎钓丰,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體每币,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡携丁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了兰怠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梦鉴。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖揭保,靈堂內(nèi)的尸體忽然破棺而出肥橙,到底是詐尸還是另有隱情,我是刑警寧澤秸侣,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布存筏,位于F島的核電站,受9級特大地震影響味榛,放射性物質(zhì)發(fā)生泄漏椭坚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一励负、第九天 我趴在偏房一處隱蔽的房頂上張望藕溅。 院中可真熱鬧,春花似錦继榆、人聲如沸巾表。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽集币。三九已至考阱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞠苟,已是汗流浹背乞榨。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留当娱,地道東北人吃既。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像跨细,于是被迫代替她去往敵國和親鹦倚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容