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;
--------------------------------------------------------------------------文章来自吴大勋(大勋哥) 链接
查看更多关于react----自定义UI组件(表单)的详细内容...