react----自定義UI組件(表單)


react組件

react組件的后綴名可以是js,也可以是jsx

需要配置webpack的解析器以及缺省的后綴名
531b3b359fdff69bd63191f101fbbd99.png
8b80f356bd25badd77c9a7ae5fc61cf3.png

重新調整代碼結構

src/index.js
dd460f1f3866c5b14ac4c593cc705fa3.png
85a49372f87d6823084dacfc985d45d5.png

React props

state 和 props 主要區別在於 props 是不可變的,而 state 可以根據用戶的交互來改變。

組件本身自己用state, 組件之間使用props(vue中組件本身data,組件之間傳值)

props的基本案例

父子組件的傳值

父組件在調用子組件的地方,添加一個自定義的屬性,屬性的值就是你需要傳遞給子組件的值,如果屬性的值是變量,boolean,number,需要使用 {}包裹

在子組件中 通過 this.props 獲取到父組件傳遞過來的數據

import React from 'react';

class Child extends React.Component {
  render () {
    console.log(this.props)
    { this.props.test }
    return (
      <div>
        <h2>props</h2>
      </div>
    )
  }
}

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
    }
  }

  render () {
    return (
      <div>
        <h2>react組件之間傳值</h2>
        <Child test="測試" />
      </div>
    )
  }
}

export default App;

如果傳遞的是一個變量

import React from 'react';

class Child extends React.Component {
  render () {
    console.log(this.props)
    { this.props.test }
    return (
      <div>
        <h2>props</h2>
        {
            //-------------------新增代碼---------------------------
        }
        {
            this.props.list.map((item, index) => (
                <p key={ index }>{ item }</p>
            ))
        }
        {
            //-------------------新增代碼---------------------------
        }
      </div>
    )
  }
}

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
        list: ['HTML5', 'JAVAEE', 'PYTHON', '物聯網', '測試', '大數據', '雲計算', 'UI']
    }
  }

  render () {
    return (
      <div>
        <h2>react組件之間傳值</h2>
        <Child test="測試" list={ this.state.list }/>
      </div>
    )
  }
}

export default App;

如果props需要要默認值呢(傳則用傳的,不傳則用默認的)

import React from 'react';

class Child extends React.Component {
  render () {
    console.log(this.props)
    { this.props.test }
    return (
      <div>
        <h2>props</h2>
        {
            this.props.list.map((item, index) => (
                <p key={ index }>{ item }</p>
            ))
        }
        {
            //-------------------新增代碼---------------------------
        }
        {
            this.props.name
        }
        {
            //-------------------新增代碼---------------------------
        }
      </div>
    )
  }
}

// ------------------新增代碼---------------------------

Child.defaultProps = {
    name: '我是默認的屬性'
}

// ------------------新增代碼---------------------------

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
        list: ['HTML5', 'JAVAEE', 'PYTHON', '物聯網', '測試', '大數據', '雲計算', 'UI']
    }
  }

  render () {
    return (
      <div>
        <h2>react組件之間傳值</h2>
        <Child test="測試" list={ this.state.list }/>
      </div>
    )
  }
}

export default App;

如果傳遞的值需要 數據類型的校驗

cnpm i prop-types -D

(React v15.5 版本后把數據類型檢驗單獨的移動到 npm 包,減少核心庫的體積)

import React from 'react';
// -----------------新增代碼---------------------------import PropTypes from 'prop-types';
class Child extends React.Component {
  render () {
    console.log(this.props)
    { this.props.test }
    return (
      <div>
        <h2>props</h2>
        {
            this.props.list.map((item, index) => (
                <p key={ index }>{ item }</p>
            ))
        }
        {
            this.props.name
        }
      </div>
    )
  }
}
Child.defaultProps = {
    name: '我是默認的屬性'
}
// ------------------新增代碼---------------------------


// 驗證方式 Child.propTypes 注意大小寫
Child.propTypes = {
    name: PropTypes.string,
    test: PropTypes.string,
    list: PropTypes.array
}
// ------------------新增代碼---------------------------

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
        list: ['HTML5', 'JAVAEE', 'PYTHON', '物聯網', '測試', '大數據', '雲計算', 'UI']
    }
  }

  render () {
    return (
      <div>
        <h2>react組件之間傳值</h2>
        <Child test="測試" list={ this.state.list }/>
      </div>
    )
  }
}

export default App;

拓展-react15.5以前組件寫法以及驗證

// 這段代碼不要在編輯器編寫,編寫無效 -- react版本var title = 'hello react';
var MyTitle = React.createClass({
    propTypes: {
        title: React.PropTypes.string.isRequired
    },
    render () {
        return (
            <div>{ this.props.title }</div>
        )
    }
})
ReactDOM.render(<MyTitle title={ tilte } />, document.getElementById('app'))

.
react props 驗證規則
https://react.docschina.org/docs/typechecking-with-proptypes.html

import PropTypes from 'prop-types';

MyComponent.propTypes = {
  // 你可以將屬性聲明為 JS 原生類型,默認情況下
  // 這些屬性都是可選的。
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,

  // 任何可被渲染的元素(包括數字、字符串、元素或數組)
  // (或 Fragment) 也包含這些類型。
  optionalNode: PropTypes.node,

  // 一個 React 元素。
  optionalElement: PropTypes.element,

  // 一個 React 元素類型(即,MyComponent)。
  optionalElementType: PropTypes.elementType,

  // 你也可以聲明 prop 為類的實例,這里使用
  // JS 的 instanceof 操作符。
  optionalMessage: PropTypes.instanceOf(Message),

  // 你可以讓你的 prop 只能是特定的值,指定它為
  // 枚舉類型。
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),

  // 一個對象可以是幾種類型中的任意一個類型
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),

  // 可以指定一個數組由某一類型的元素組成
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

  // 可以指定一個對象由某一類型的值組成
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

  // 可以指定一個對象由特定的類型值組成
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),
  
  // An object with warnings on extra properties
  optionalObjectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),   

  // 你可以在任何 PropTypes 屬性后面加上 `isRequired` ,確保
  // 這個 prop 沒有被提供時,會打印警告信息。
  requiredFunc: PropTypes.func.isRequired,

  // 任意類型的數據
  requiredAny: PropTypes.any.isRequired,

  // 你可以指定一個自定義驗證器。它在驗證失敗時應返回一個 Error 對象。
  // 請不要使用 `console.warn` 或拋出異常,因為這在 `onOfType` 中不會起作用。
  customProp: function(props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },

  // 你也可以提供一個自定義的 `arrayOf` 或 `objectOf` 驗證器。
  // 它應該在驗證失敗時返回一個 Error 對象。
  // 驗證器將驗證數組或對象中的每個值。驗證器的前兩個參數
  // 第一個是數組或對象本身
  // 第二個是他們當前的鍵。
  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })};

React 事件處理

react元素的事件處理和DOM元素類似,有一點語法的不同

  • react事件綁定采用駝峰式命名,而不是小寫
  • 如果采用jsx語法 需要傳入一個函數作為事件處理函數,而不是一個字符串(DOM元素寫法)

DOM

<button onclick="fn()"></button>

React

<button onClick={ this.fn }></button>
<button onClick={ () => {} }></button>
  • 構造方法改變this -- 給組件的實例添加新的方法
import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    // 這里綁定時必須的,這樣 this 才能在回調函數中使用
    // 給當前的組件添加了一個實例方法, 這個類中定義了一個方法,改變了this指向
    this.hanleClickFn = this.hanleClick.bind(this)
    this.state = {
      isToggleOn: true // 默認按鈕為開
    }
  }
  // 必須小心對待jsx中的this,類的方法默認不會綁定當前組件的this
  // 可以在構造方法將自定義的函數綁定到當前的組件實例中
  hanleClick () {
    console.log('按鈕被點擊了', this)
    // 改變react狀態   this.setState({ key: val })
    // react 改變狀態   獲取狀態   處理狀態  修改數據
    // 不能使用 this.state.isToggleOn = !this.state.isToggleOn 違背了react的原則
    let isToggleOn = this.state.isToggleOn
    isToggleOn = !isToggleOn
    // 狀態的改變會引起視圖的二次渲染
    this.setState({
      isToggleOn: isToggleOn
    })
  }
  render () {
    return (
      <div>
        <h2>事件處理</h2>
        {/* 點擊以下按鈕實現按鈕的開關 */}
        <button onClick= { this.hanleClickFn }>
          { this.state.isToggleOn ? '開' : '關' }
        </button>
      </div>
    )
  }
}

export default App;

710f4b6846731b46438e0c57498806a0.png

  • 直接改變this指向 - 不會給組件實例添加新的方法 (推薦)
import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      isToggleOn: true // 默認按鈕為開
    }
  }
  hanleClick () {
    console.log('按鈕被點擊了', this)
    let isToggleOn = this.state.isToggleOn
    isToggleOn = !isToggleOn
    this.setState({
      isToggleOn
    })
  }
  render () {
    return (
      <div>
        <h2>事件處理</h2>
        {/* 點擊以下按鈕實現按鈕的開關 */}
        <button onClick= { this.hanleClick.bind(this) }>
          { this.state.isToggleOn ? '開' : '關' }
        </button>
      </div>
    )
  }
}

export default App;

  • 傳入函數作為事件處理函數 --- (推薦)
import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      isToggleOn: true // 默認按鈕為開
    }
  }
  render () {
    return (
      <div>
        <h2>事件處理</h2>
        {/* 點擊以下按鈕實現按鈕的開關 */}
        <button onClick= { () => {
          console.log(this)
          let isToggleOn = this.state.isToggleOn
          isToggleOn = !isToggleOn
          this.setState({
            isToggleOn
          })
        } }>
          { this.state.isToggleOn ? '開' : '關' }
        </button>
      </div>
    )
  }
}

export default App;

綁定事件傳遞參數

  • 傳遞事件對象參數
import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      isToggleOn: true // 默認按鈕為開
    }
  }

  getEvent (event) {
    console.log(event)
  }

  render () {
    return (
      <div>
        <h2>事件處理</h2>
        {/* 點擊以下按鈕實現按鈕的開關 */}
        <button onClick= { this.getEvent }>獲取事件對象</button>
        <button onClick= { this.getEvent.bind(this) }>獲取事件對象2</button>

        <button onClick= { (event) => {
          console.log(event)
          let isToggleOn = this.state.isToggleOn
          isToggleOn = !isToggleOn
          this.setState({
            isToggleOn
          })
        } }>
          { this.state.isToggleOn ? '開' : '關' }
        </button>
      </div>
    )
  }
}

export default App;

  • 傳遞自定義的參數
import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      isToggleOn: true // 默認按鈕為開
    }
  }

  // 事件對象參數在最后, 因為不一定會用到事件對象
  // getEvent (params, event) {
  //   console.log(params)
  //   console.log(event)
  // }

  // 事件對象不是必須的參數
  getEvent (params) {
    console.log(params)
    console.log(event)
  }

  getEvent1 (params1, params2) {
    console.log(params1, params2)
  }
  render () {
    let a = 10
    return (
      <div>
        <h2>事件處理</h2>
        {/* 點擊以下按鈕實現按鈕的開關 */}
        <button onClick= { this.getEvent.bind(this, '哈哈哈') }>傳遞普通的值</button>
        <button onClick= { this.getEvent1.bind(this, '哈哈哈', '啦啦啦') }>傳遞普通的值</button>

        <button onClick = { () => {
          console.log(a)
          console.log(event)
        }}>箭頭函數傳值</button>

        <button onClick= { (event) => {
          console.log(event)
          let isToggleOn = this.state.isToggleOn
          isToggleOn = !isToggleOn
          this.setState({
            isToggleOn
          })
        } }>
          { this.state.isToggleOn ? '開' : '關' }
        </button>
      </div>
    )
  }
}

export default App;

React表單

表單元素會保留一些內部狀態

import React from 'react';
class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      username: '',
      password: ''
    }
  }

  handleChange (event) {
    console.log(event.target.value)
    this.setState({
      username: event.target.value
    })
  }

  render () {
    return (
      <div>
        <input type="text" value = { this.state.username } onChange = { this.handleChange.bind(this) }/>
        <input type="password" value={ this.state.password }onChange = { (event) => {
          this.setState({
            password: event.target.value
          })
        } }/>
      </div>
    )
  }
}

export default App;

  • 假設表單組件在子組件中

需要在父組件通過事件句柄,並且作為屬性傳遞到子組件中

封裝UI庫之-輸入框組件

屬性 描述 默認值 是否必傳
type 類型 ‘text'
placeholder 占位符 ‘'
value 輸入框的值 ‘'
error 提示信息 ‘'
clearable 清除按鈕 false
事件 描述 默認值 是否必傳
onChange 輸入框值發生變化  
import React from 'react';

class MyInput extends React.Component {
    render () {
        return (
        <div>
            <input
                type={this.props.type || 'text'}
                placeholder = { this.props.placeholder || '' }
                value = { this.props.value }
                onChange = { this.props.onChange }
            />
            {
                this.props.clearable && this.props.value.length > 0 ? <span style = { { display: 'inline-block', width: '20px', height: '20px', background: '#333', color: '#fff', borderRadius: '50%', textAlign: 'center' } }>×</span> : ''
            }
            { this.props.error || ''}
        </div>
        )
    }
}

調用組件

import React from 'react';

class MyInput extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            username: '',
            usernametip: '',
            tel: '',
            teltip: '',
            password: '',
            passwordtip: '',
        }
    }
    usernameChange () {
        this.setState({
            username: event.target.value
        })
    }
    
    passwordChange () {
        this.setState({
            password: event.target.value
        })
    }
    render () {
        return (
            <div>
                { /* 基本用法 */ }
                <MyInput 
                    value = { this.state.username }
                    onChange = { this.usernameChange.bind(this) }
                />
                 { /* 添加密碼,占位符 */ }
                <MyInput 
                    type="password"
                    placeholder="請輸入密碼"
                    value = { this.state.password }
                    onChange = { this.passwordChange.bind(this) }
                />
                 { /* 添加密碼,占位符,添加一個清除按鈕 */ }
                <MyInput 
                    type="password"
                    placeholder="請輸入密碼"
                    value = { this.state.password }
                    onChange = { this.passwordChange.bind(this) }
                    clearable
                />
                 { /* 添加密碼,占位符,添加一個清除按鈕, 添加錯誤提交信息*/ }
                <MyInput 
                    type="password"
                    placeholder="請輸入密碼"
                    value = { this.state.password }
                    onChange = { this.passwordChange.bind(this) }
                    error = { this.state.usernametip }
                    clearable
                />
            </div>
        )
    }
}

react版本TodoList

  • 表單和列表在一個組件
import React from 'react';

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      list: [],
      username: ''
    }
  }
  getUsername () {
    this.setState({
      username: event.target.value
    })
  }
  addUser () {
    const list = this.state.list
    list.push(this.state.username)
    this.setState({
      list
    })
  }
  render () {
    return (
      <div>
        <input type="text" value={ this.state.username } onChange = { this.getUsername.bind(this) }/>
        <button onClick={ this.addUser.bind(this) }>添加</button>
        <ul>
          {
            this.state.list.length > 0 ? this.state.list.map((item, index) => {
              return (
                <li key={ index }>
                  { item }
                  <button onClick = { () => {
                    const list = this.state.list
                    list.splice(index, 1)
                    this.setState({ 
                      list
                    })
                  } }>刪除</button>
                </li>
              )
            }) : <li>暫無數據</li>
          }
        </ul>
      </div>
    )
  }
}

export default App;

  • 表單在父組件,列表在子組件
import React from 'react';

// 函數式組件不可以訪問this,好友默認的參數為propsconst List = (props) => (
  <ul>
    {
      props.list.length > 0 ? props.list.map((item, index) => {
        return (
          <li key={ index }>
            { item }
            <button onClick = { () => {
              props.deleteItem(index)
            } }>刪除</button>
          </li>
        )
      }) : <li>暫無數據</li>
    }
  </ul>
)

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      list: [],
      username: ''
    }
  }
  getUsername () {
    this.setState({
      username: event.target.value
    })
  }
  addUser () {
    const list = this.state.list
    list.push(this.state.username)
    this.setState({
      list
    })
  }
  deleteItem (index) { // index參數是子組件傳遞的
    console.log(index)
    const list = this.state.list
    list.splice(index, 1)
    this.setState({
      list
    })
  }
  render () {
    return (
      <div>
        <input type="text" value={ this.state.username } onChange = { this.getUsername.bind(this) }/>
        <button onClick={ this.addUser.bind(this) }>添加</button>
        <List list = { this.state.list } deleteItem = { this.deleteItem.bind(this) }/>
      </div>
    )
  }
}

export default App;


--------------------------------------------------------------------------文章來自吳大勛(大勛哥)鏈接


免責聲明!

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



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