react組件
react組件的后綴名可以是js,也可以是jsx
需要配置webpack的解析器以及缺省的后綴名
重新調整代碼結構
src/index.js
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;
- 直接改變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;
--------------------------------------------------------------------------文章來自吳大勛(大勛哥)鏈接