最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React?props全面詳細(xì)解析

 更新時(shí)間:2022年10月22日 09:40:04   作者:YinJie…  
props?是?React?組件通信最重要的手段,它在?React?的世界中充當(dāng)?shù)慕巧鞘种匾?。學(xué)好?props?可以使組件間通信更加靈活,同時(shí)文中會(huì)介紹一些?props?的操作技巧,和學(xué)會(huì)如何編寫嵌套組件

一、Props 是什么

先來看一個(gè) demo :

function Chidren(){
  return <div> 我是子組件 </div>
}
/* props 接受處理 */
function Father(props) {
      const {  children , mes , renderName , say ,Component } = props
      const renderFunction = children[0]
      const renderComponent = children[1]
      /* 對(duì)于子組件,不同的props是怎么被處理 */
      return (
        <div>
            { renderFunction() }
            { mes }
            { renderName() }
            { renderComponent }
            <Component />
            <button onClick={ () => say() } > 觸發(fā)更改 </button>
        </div> )
}
/* props 定義綁定 */
class App extends React.Component{
  state={  
      mes: "hello,React"
  }
  node = null
  say= () =>  this.setState({ mes:'let us learn React!' })
  render(){
      return <div>
          <Father  
             mes={this.state.mes}  // ① props 作為一個(gè)渲染數(shù)據(jù)源
             say={ this.say  }     // ② props 作為一個(gè)回調(diào)函數(shù) callback
             Component={ Chidren } // ③ props 作為一個(gè)組件
             renderName={ ()=><div> my name is YinJie </div> } // ④ props 作為渲染函數(shù)
          >
              { ()=> <div>hello,world</div>  } { /* ⑤render props */ }
              <Chidren />             { /* ⑥r(nóng)ender component */ }
          </Father>
      </div>
  }
}

我們看一下輸出結(jié)果:

當(dāng)點(diǎn)擊觸發(fā)更改時(shí)就能夠調(diào)用回調(diào)更改數(shù)據(jù)源:

所以 props 可以是:

① props 作為一個(gè)子組件渲染數(shù)據(jù)源。

② props 作為一個(gè)通知父組件的回調(diào)函數(shù)。

③ props 作為一個(gè)單純的組件傳遞。

④ props 作為渲染函數(shù)。

⑤ render props , 和④的區(qū)別是放在了 children 屬性上。

⑥ render component 插槽組件。

二、props children模式

我們先來看看 prop + children 的幾個(gè)基本情況:

1. props 插槽組件

<Container>
    <Children>
</Container>

上述可以在 Container 組件中,通過 props.children 屬性訪問到 Children 組件,為 React element 對(duì)象。

作用:

  • 可以根據(jù)需要控制 Children 是否渲染。
  • 像上一節(jié)所說的, Container 可以用 React.cloneElement 強(qiáng)化 props (混入新的 props ),或者修改 Children 的子元素。

舉一個(gè)用React.cloneElement 強(qiáng)化 props 的例子,多用于編寫組件時(shí)對(duì)子組件混入新的 props,下面我們要做一個(gè)導(dǎo)航組件,我們希望它的結(jié)構(gòu)如下:

<Menu>
    <MenuItem >
        active
    </MenuItem>
    <MenuItem>
        disabled
    </MenuItem>
    <MenuItem >
        xyz
    </MenuItem>
</Menu>

我們想給每個(gè) MenuItem 子組件都添加 index 屬性,這個(gè)事情不應(yīng)該讓用戶手動(dòng)添加,最好是可以在 Menu 組件中自動(dòng)為每個(gè) MenuItem 子組件添加上,并且 Menu 組件還應(yīng)該判斷子組件的類型,如果子組件的類型不是 MenuItem 組件就報(bào)錯(cuò)。

Menu.tsx:

const Menu: React.FC<MenuProps> = (props) => {
    // ... 一些操作
    const renderChildren = () => { // 讓子級(jí)的children都是 menuItem,有不是的就報(bào)錯(cuò)
        return React.Children.map(children, (child, index) => {
            const childElement = child as React.FunctionComponentElement<MenuItemProps>
            const { displayName } = childElement.type
            if(displayName === 'MenuItem' || displayName === "SubMenu") {
                return React.cloneElement(childElement, { index: index.toString() })
            } else {
                console.error('warning: Menu has a child whitch is not a MenuItem')
            }
        })
    }
    return (
        <ul className={classes} style={style} data-testid="test-menu">
            <MenuContext.Provider value={passedContext}>
                {renderChildren()}
            </MenuContext.Provider>
        </ul>
    )
}

在 Menu 組件中我們通過 React.children.map 來循環(huán)子組件,通過 child.type 可以獲取到每個(gè)子組件的 displayName 靜態(tài)屬性,這個(gè)在子組件中有定義:

通過子組件的 displayName 來判斷是否是我們需要的 MenuItem,如果是的話就調(diào)用 React.cloneElement 來為子組件添加 index 屬性。

2. render props模式

<Container>
   { (ContainerProps)=> <Children {...ContainerProps}  /> }
</Container>

這種情況,在 Container 中, props.children 屬性訪問到是函數(shù),并不是 React element 對(duì)象,我們應(yīng)該調(diào)用這個(gè)函數(shù):

function  Container(props) {
    const  ContainerProps = {
        name: 'alien',
        mes:'let us learn react'
    }
     return  props.children(ContainerProps)
}

這種方式作用是:

1 根據(jù)需要控制 Children 渲染與否。

2 可以將需要傳給 Children 的 props 直接通過函數(shù)參數(shù)的方式傳遞給執(zhí)行函數(shù) children 。

3. render props模式

如果 Container 的 Children 既有函數(shù)也有組件,這種情況應(yīng)該怎么處理呢?

<Container>
    <Children />
    { (ContainerProps)=> <Children {...ContainerProps} name={'haha'}  />  }
</Container>
const Children = (props)=> (<div>
    <div>hello, my name is {  props.name } </div>
    <div> { props.mes } </div>
</div>)
function  Container(props) {
    const ContainerProps = {
        name: 'alien',
        mes:'let us learn react'
    }
     return props.children.map(item=>{
        if(React.isValidElement(item)){ // 判斷是 react elment  混入 props
            return React.cloneElement(item,{ ...ContainerProps },item.props.children)
        }else if(typeof item === 'function'){
            return item(ContainerProps)
        }else return null
     })
}
const Index = ()=>{
    return <Container>
        <Children />
        { (ContainerProps)=> <Children {...ContainerProps} name={'haha'}  />  }
    </Container>
}

這種情況需要先遍歷 children ,判斷 children 元素類型:

  • 針對(duì) element 節(jié)點(diǎn),通過 cloneElement 混入 props ;
  • 針對(duì)函數(shù),直接傳遞參數(shù),執(zhí)行函數(shù)。

三、進(jìn)階實(shí)踐

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的<Form> <FormItem>嵌套組件

接下來到實(shí)踐環(huán)節(jié)了。需要編寫一個(gè)實(shí)踐 demo ,用于表單狀態(tài)管理的<Form><FormItem>組件

  • <Form>用于管理表單狀態(tài);
  • <FormItem>用于管理<Input>輸入框組件。,

編寫的組件能夠?qū)崿F(xiàn)的功能是:

Form組件可以被 ref 獲取實(shí)例。然后可以調(diào)用實(shí)例方法submitForm獲取表單內(nèi)容,用于提交表單,resetForm方法用于重置表單。

Form組件自動(dòng)過濾掉除了FormItem之外的其他React元素

FormItem中 name 屬性作為表單提交時(shí)候的 key ,還有展示的 label 。

FormItem可以自動(dòng)收集<Input/>表單的值。

App.js:

import React, { useState, useRef } from "react";
import Form from './Form'
import FormItem from './FormItem'
import Input from './Input'
function App () {
  const form =  useRef(null)
  const submit =()=>{
      /* 表單提交 */
      form.current.submitForm((formValue)=>{ // 調(diào)用 form 中的submitForm方法
          console.log(formValue)
      })
  }
  const reset = ()=>{
      /* 表單重置 */
      form.current.resetForm() //調(diào)用 form 中的 resetForm 方法
  }
  return <div className='box' >
      <Form ref={ form } >
          <FormItem name="name" label="我是"  >
              <Input   />
          </FormItem>
          <FormItem name="mes" label="我想對(duì)大家說"  >
              <Input   />
          </FormItem>
          <FormItem name="lees" label="ttt"  >
              <Input   />
          </FormItem>
      </Form>
      <div className="btns" >
          <button className="searchbtn"  onClick={ submit } >提交</button>
          <button className="concellbtn" onClick={ reset } >重置</button>
      </div>
  </div>
}
export default App

Form.js:

class Form extends React.Component{
    state={
        formData:{}
    }
    /* 用于提交表單數(shù)據(jù) */
    submitForm=(cb)=>{
        cb({ ...this.state.formData })
    } 
    /* 獲取重置表單數(shù)據(jù) */
    resetForm=()=>{
       const { formData } = this.state
       Object.keys(formData).forEach(item=>{
           formData[item] = ''
       })
       this.setState({
           formData
       })
    }
    /* 設(shè)置表單數(shù)據(jù)層 */
    setValue=(name,value)=>{
        this.setState({
            formData:{
                ...this.state.formData,
                [name]:value
            }
        })
    }
    render(){
        const { children } = this.props
        const renderChildren = []
        React.Children.forEach(children,(child)=>{
            if(child.type.displayName === 'formItem'){
                const { name } = child.props
                /* 克隆`FormItem`節(jié)點(diǎn),混入改變表單單元項(xiàng)的方法 */
                const Children = React.cloneElement(child,{ 
                    key:name ,                             /* 加入key 提升渲染效果 */
                    handleChange:this.setValue ,           /* 用于改變 value */
                    value:this.state.formData[name] ||  '' /* value 值 */
                },child.props.children)
                renderChildren.push(Children)
            }
        })
        return renderChildren
    }
}
/* 增加組件類型type  */
Form.displayName = 'form'

設(shè)計(jì)思想:

  • 首先考慮到<Form>在不使用forwardRef前提下,最好是類組件,因?yàn)橹挥蓄惤M件才能獲取實(shí)例。
  • 創(chuàng)建一個(gè) state 下的 formData屬性,用于收集表單狀態(tài)。
  • 要封裝重置表單,提交表單,改變表單單元項(xiàng)的方法。
  • 要過濾掉除了FormItem元素之外的其他元素,那么怎么樣知道它是不是FormItem,這里教大家一種方法,可以給函數(shù)組件或者類組件綁定靜態(tài)屬性來證明它的身份,然后在遍歷 props.children 的時(shí)候就可以在 React element 的 type 屬性(類或函數(shù)組件本身)上,驗(yàn)證這個(gè)身份,在這個(gè) demo 項(xiàng)目,給函數(shù)綁定的 displayName 屬性,證明組件身份。
  • 要克隆FormItem節(jié)點(diǎn),將改變表單單元項(xiàng)的方法 handleChange 和表單的值 value 混入 props 中。

FormItem.js:

function FormItem(props){
    const { children , name  , handleChange , value , label  } = props
    const onChange = (value) => {
        /* 通知上一次value 已經(jīng)改變 */
        handleChange(name,value)
    }
   return <div className='form' >
       <span className="label" >{ label }:</span>
       {
            React.isValidElement(children) && children.type.displayName === 'input' 
            ? React.cloneElement(children,{ onChange , value })
            : null
       }
   </div>    
}
FormItem.displayName = 'formItem'

設(shè)計(jì)思想:

  • FormItem一定要綁定 displayName 屬性,用于讓<Form>識(shí)別<FormItem />
  • 聲明onChange方法,通過 props 提供給<Input>,作為改變 value 的回調(diào)函數(shù)。
  • FormItem過濾掉除了input以外的其他元素。

Input.js:

/* Input 組件, 負(fù)責(zé)回傳value值 */
function Input({ onChange , value }){
    return  <input className="input"  onChange={ (e)=>( onChange && onChange(e.target.value) ) } value={value}  />
}
/* 給Component 增加標(biāo)簽 */
Input.displayName = 'input'

設(shè)計(jì)思想:

  • 綁定 displayName 標(biāo)識(shí)input。
  • inputDOM 元素,綁定 onChange 方法,用于傳遞 value 。

下面通過函數(shù)組件再重寫一下:

App.js,F(xiàn)ormItem.js 和 Input.js 還是一樣的,F(xiàn)orm.js使用了 hooks 鉤子來管理狀態(tài),并且通過forwardRef, useImperativeHandle,讓 App 組件訪問到 Form 中的方法:

import React, { useState, forwardRef, useImperativeHandle } from "react"
const Form = (props, ref) =>{
    const { children } = props
    const [ formData, setFormData ] = useState({})
    useImperativeHandle(ref, () => ({
        submitForm: submitForm,
        resetForm: resetForm
    }))
    /* 用于提交表單數(shù)據(jù) */
    const submitForm=(cb)=>{
        cb(formData)
    } 
    /* 獲取重置表單數(shù)據(jù) */
    const resetForm=()=>{
        const newData = formData
       Object.keys(newData).forEach(item=>{
          newData[item] = ''
       })
       setFormData(newData)
    }
    /* 設(shè)置表單數(shù)據(jù)層 */
    const setValue=(name,value)=>{
        setFormData({
            ...formData,
            [name]:value
        })
    }
    const renderChildren = () => {
        return React.Children.map(children,(child)=>{
            if(child.type.displayName === 'formItem'){
                const { name } = child.props
                /* 克隆`FormItem`節(jié)點(diǎn),混入改變表單單元項(xiàng)的方法 */
                const Children = React.cloneElement(child,{ 
                    key:name ,                             /* 加入key 提升渲染效果 */
                    handleChange: setValue ,           /* 用于改變 value */
                    value: formData[name] ||  '' /* value 值 */
                },child.props.children)
                return Children
            }
        })
    }
    return ( 
          renderChildren()
        )
}
/* 增加組件類型type  */
Form.displayName = 'form'
export default forwardRef(Form) 

啟動(dòng)項(xiàng)目,查看效果:

點(diǎn)擊提交,我們?cè)谳斎肟蚶镙斎氲膬?nèi)容就能顯示在控制臺(tái)上。

為了體現(xiàn)出咱們這個(gè)嵌套組件的高可復(fù)用性,我們可以在根組件中隨意添加子項(xiàng):

到此這篇關(guān)于React props全面詳細(xì)解析的文章就介紹到這了,更多相關(guān)React props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解react中useCallback內(nèi)部是如何實(shí)現(xiàn)的

    詳解react中useCallback內(nèi)部是如何實(shí)現(xiàn)的

    前幾天有人在問在useCallback函數(shù)如果第二個(gè)參數(shù)為空數(shù)組, 為什么拿不到最新的state值,那么這一章就來分析一下useCallback內(nèi)部是如何實(shí)現(xiàn)的,感興趣的小伙伴跟著小編一起來學(xué)習(xí)吧
    2023-07-07
  • React中的生命周期詳解

    React中的生命周期詳解

    這篇文章主要介紹了React中的生命周期,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-09-09
  • React-vscode使用jsx語法的問題及解決方法

    React-vscode使用jsx語法的問題及解決方法

    很多朋友在安裝插件ES7 React/Redux/GraphQL/React-Native snippets還是不能完全支持jsx語法,糾結(jié)是什么原因呢,該如何處理呢,下面小編給大家分享本文幫助大家解決React-vscode使用jsx語法問題,感興趣的朋友一起看看吧
    2021-06-06
  • React項(xiàng)目動(dòng)態(tài)修改主題顏色的方案

    React項(xiàng)目動(dòng)態(tài)修改主題顏色的方案

    這篇文章主要介紹了React項(xiàng)目動(dòng)態(tài)修改主題顏色的方案,文中通過代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2025-01-01
  • 深入探討前端框架react

    深入探討前端框架react

    本文帶領(lǐng)大家一起探討前端框架react,涉及到前端框架react相關(guān)知識(shí),對(duì)前端框架react相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • React如何動(dòng)態(tài)控制偽元素樣式

    React如何動(dòng)態(tài)控制偽元素樣式

    這篇文章主要介紹了React如何動(dòng)態(tài)控制偽元素樣式問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題

    react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題

    這篇文章主要介紹了react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • React獲取input值并提交的2種方法實(shí)例

    React獲取input值并提交的2種方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于React獲取input值并提交的2種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 詳解React 的幾種條件渲染以及選擇

    詳解React 的幾種條件渲染以及選擇

    這篇文章主要介紹了詳解React 的幾種條件渲染以及選擇,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10
  • 適用于React?Native?旋轉(zhuǎn)木馬應(yīng)用程序介紹

    適用于React?Native?旋轉(zhuǎn)木馬應(yīng)用程序介紹

    這篇文章主要介紹了適用于React?Native?旋轉(zhuǎn)木馬應(yīng)用程序介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10

最新評(píng)論

平塘县| 巴南区| 永年县| 芜湖县| 多伦县| 沿河| 信宜市| 溧阳市| 宜黄县| 祁东县| 靖边县| 太谷县| 鹤壁市| 内黄县| 孟津县| 陆良县| 阿尔山市| 穆棱市| 营口市| 永德县| 内江市| 孟州市| 南京市| 金溪县| 砀山县| 深水埗区| 永兴县| 五常市| 中卫市| 罗源县| 潮安县| 晋城| 仁化县| 牟定县| 楚雄市| 新巴尔虎右旗| 富顺县| 祥云县| 库尔勒市| 陇西县| 新安县|