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;
--------------------------------------------------------------------------文章来自吴大勋(大勋哥)链接