React
import React from 'react'
一、jsx
1.jsx是一个变量也是一个对象
2.jsx可以以使用静态和动态属性
3.jsx本身就是表达式,内部也可以使用表达式(用大括号包裹)
4.jsx可以任意嵌套(用大括号包裹)
5.jsx中的注释也是变量(用大括号包裹)
6.jsx中可以绑定变量
const ele = <h2>我是jsx变量<h2>
(具体效果参考以下类组件项)
二、react组件定义方式
类组件
export default class TestJsx extends React.Component {
constructor(props) {
super(props)
this.state = {
msg:'hello msg jsx',
color:'red',
style:{color:pink,font-size:50px}
}
}
// 外部jsx变量嵌套
createChild() {
return (
<div>
<span>我是嵌套的jsx变量</span>
{ele}
</div>
)
}
// jsx事件方法
changeColor() {
this.setState({
color:'blue'
})
}
render() {
return (
<div>
<h1>JSX</h1>
{ele}
<h2 title='jsx'>jsx静态属性<h2>
<h2 className={this,state.color}>JSX动态属性</h2>
<h2>{this.state.msg}</h2>
<h2>{this.state.createChild()}</h2>
{/* 这是注释 */}
<button onClick={this.changeColor.bind(this)}>jsx的事件</button>
<h2 style={{color:'orange',font-size:'40px'}}>jsx内置样式</h2>
<h2 style={this.state.style}>jsx内置样式</h2>
</div>
)
}
}
函数组件(无状态组件)
1.它没有状态state
2.它没有生命周期
3.它没有this
4.它唯一好处是性能好,这是react性能优化方式之一
props:
1.用于父组件传子组件值
2.只读,不能操作(不能修改,不能用于赋值)
3.props和state没有关系,不能相互赋值
export default function Child1(props) {
return(
<div className='child'>
<h2>这是一个函数组件,{props.aaa}</h2>
{props.children}
</div>
)
}
<Child1 aaa='我是父组件传的值' >
<span>我是父组件传递的标签元素</span>
</Child1>
ES5组件
React.createClass
var InputControlES5 = React.createClass({
propTypes: {//定义传入props中的属性各种类型
initialValue: React.PropTypes.string
},
defaultProps: { //组件默认的props对象
initialValue: ''
},
// 设置 initial state
getInitialState: function() {//组件相关的状态对象
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({ //this represents react component instance
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
});
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
React.Component
class InputControlES6 extends React.Component {
constructor(props) {
super(props);
// 设置 initial state
this.state = {
text: props.initialValue || 'placeholder'
};
// ES6 类中函数必须手动绑定
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
Hooks组件
高阶组件
三、事件处理
事件规范‘on+事件’
// 事件如何传参?
// bind()方式绑定,this.clickHandle.bind(this, ‘arg1’, ‘arg2’)
// 箭头函数方式绑定,(e)=>this.clickHandle(‘arg1’, e, ‘arg2’)
export default class TestEvent extends React.Component {
constructor(props) {
super(props)
this.state = {
num: 1
}
this.clickHandle1 = this.clickHandle.bind(this)
}
clickHandle() {
this.state.num++
this.setState({
num: this.state.num
})
}
// stop(e) {
// // 默认事件阻止
// e.preventDefault()
// // 冒泡事件阻止
// e.stopPropagation()//w3c标准
// e.cancelBubble = true//ie
// }
render() {
return (
<div>
<h2>{this.state.num}</h2>
{/* 方式一 */}
<div onClick={this.clickHandle.bind(this)}>写法一</div>
<div onClick={this.clickHandle1}>写法二</div>
{/* 方式二 */}
<div onClick={() => this.clickHandle(this)}>写法三</div>
</div>
)
}
}
四、条件渲染
import React from 'react'
export default class TestCondition extends React.Component {
constructor(props) {
super(props)
this.state = {
bol1: true,
bol2: false,
bol3: 1,
dis: 'block'
}
}
creatViews() {
let { bol3 } = this.state
let ele
switch (bol3) {
case 1:
ele = <div>111111</div>
break;
case 2:
ele = <div>222222</div>
break;
default:
ele = <div>555555</div>
break;
}
return ele
}
render() {
let { bol1, bol2, dis } = this.state
return (
<div>
<h1>条件渲染</h1>
{bol1 && <div>111111</div>}
<hr />
{bol2 && <div>222222</div>}
{!bol2 && <div>333333</div>}
<hr />
{bol2 ? <div>222222</div> : <div>333333</div>}
<hr />
{this.creatViews()}
<hr/>
<div style={{display:dis}}>666666</div>
</div>
)
}
}
五、列表渲染
import React from 'react'
export default class TestCondition extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [
{ id: 1, name: 'list1' },
{ id: 2, name: 'list2' },
{ id: 3, name: 'list3' },
{ id: 4, name: 'list4' },
{ id: 5, name: 'list5' },
]
}
}
// 方式二
createList1() {
let { list } =this.state
return list.map(ele=>(
<div key={ele.id}>{ele.name}</div>
))
}
// 方式三
createList2() {
let { list } =this.state
let arr = []
list.map(ele=>{
arr.push(
<div key={ele.id}>{ele.name}</div>
)
})
return arr
}
render() {
let { list } = this.state
return (
<div>
<h1>列表渲染</h1>
{list.map(ele => (
<div key={ele.id}>{ele.name}</div>
))}
<hr/>
{this.createList1()}
<hr/>
{this.createList2()}
</div>
)
}
}
六、父子组件传值
1、父组件传值子组件:
在父组件的render() 的jsx中,自定义属性名,并赋需要传的值
2、子组件接收父组件:
使用this.props.自定义属性名获取传递的值
3、子传父值
在父组件的render() 的jsx中,自定义事件名,并赋事件方法
在子组件中用**this.props.事件名(子传给父的值)**给父组件传值
4、例子:
子组件
import React from 'react'
export default class List extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [
{ id: 1, name: 'Q' },
{ id: 2, name: 'S' },
{ id: 3, name: 'D' },
{ id: 4, name: 'Y' },
]
}
}
langChange(id) {
console.log('传递的值',id);
this.props.onChange(id)
}
creatList() {
let { list } = this.state
let { index } = this.props
return (list.map(ele =>
<span
className={index == ele.id ? 'on' : ''}
onClick={this.langChange.bind(this,ele.id)}
key={ele.id}>
{ele.name}
</span>
))
}
render() {
return (
<div>
{/* <div className='language'> */}
{this.creatList()}
{/* </div> */}
</div>
)
}
}
import Child1 from './study/Child1'
export {
Child1
}
父组件
import React from 'react'
import {Child1} from '@/components/index.js'
export default class TestList extends React.Component{
constructor(props) {
super(props)
this.state = {
index:1
}
}
listHandle(id) {
console.log('父接收的值:',id);
this.setState({index:id})
}
render() {
let { index } = this.state
return (
<div>
<h1>测试父子组件通信</h1>
<Child1 index={index} onChange={this.listHandle.bind(this)} />
</div>
)
}
}
七、Props
import React from 'react'
// 函数式组件(无状态组件)
// 它没有状态state
// 它没有生命周期,不能使用render
// 它也没有this
// 它唯一好处是性能好,这是react性能优化方式之一
// props是父子之间纽带
// props是只读的,不能改
// props不能赋值给state。props和state没有关系,不能相互赋值。
export default function Child1(props) {
return(
<div className='child'>
<h2>{props.aaa}</h2>
<h2>{props.bbb}</h2>
{/* 把父组件传递过的jsx变量渲染出来 */}
{ props.children }
</div>
)
}
import Child1 from './study/Child1'
import Child2 from './study/Child2'
export {
Child1,
Child2
}
import React from 'react'
import { Child2 } from '@/components'
export default class TestProps extends React.Component {
constructor(props) {
super(props)
// 在这里声明的变量一旦发生变化,视图自动更新(单向绑定)
this.state = {
msg: 'hello react',
bbb: 'bbb'
}
}
// 自定义方法
changeMsg() {
let num = Math.random()
// 用于改变state的,这方法是异步的
// setState()可以接收第二参数,是一个函数,表示当前异步任务完成的回调
this.setState({msg: num}, ()=>{
console.log('更新完成')
})
}
render() {
let { msg, bbb } = this.state
msg = msg + ' !!!!'
return (
<div>
<h1>测试state和props</h1>
<h2>
{msg}
<button onClick={this.changeMsg.bind(this)}>改变msg</button>
{/* aaa是静态传值, bbb是动态传值 */}
<Child2 aaa='aaa' bbb={bbb}>
<a href="https://baidu.com">百度</a><br/>
<a href="https://baidu.com">小米</a>
</Child2>
</h2>
</div>
)
}
}
八、表单
受控表单:
value和onChange必须配合使用,那么这种表单就是受控表单
1.单向绑定的
2.表单的value值由state来决定和控制
import React from 'react'
export default class TestFrom extends React.Component{
constructor(props) {
super(props)
this.state = {
name:'1'
}
}
submit(e) {
console.log('表单测试');
console.log(this.state.name);
}
nameChange(e) {
this.setState({
name:e.target.value,
})
}
render() {
let {name} = this.state
return (
<div style={{margin:"100px auto",width:"300px"}}>
<input type='text' value={name} onChange={this.nameChange.bind(this)} />
<button onClick={this.submit.bind(this)}>提交</button>
</div>
)
}
}
非受控表单:
1.它的value不受state控制
2.React强烈建议,不要使用非受控表单(除文件上传表单外)
//非受控表单
<input type="text" id='ipt'></input>
//获取表单值
document.getElementById('ipt').value
九、状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
import React from 'react'
import { LiftA,LiftB } from '@/components';
export default class TestLeft extends React.Component{
constructor(props) {
super(props)
this.state={
msg:'1321',
}
}
onPChange(val) {
this.setState({ msg:val})
}
render() {
let { msg } = this.state
return(
<div>
<h3>状态提升</h3>
<div>
<LiftA msg={msg} />
<hr/>
<LiftB value={msg} onChange={this.onPChange.bind(this)}/>
</div>
</div>
)
}
}
import React from 'react'
export default class TestLeft extends React.Component{
render() {
let {msg} = this.props
return(
<div>
<h3>组件A</h3>
<div>
<h1>{msg}</h1>
</div>
</div>
)
}
}
import React from 'react'
export default class TestLeft extends React.Component{
onChildChange(e) {
this.props.onChange(e.target.value);
}
render() {
let { value } = this.props
return(
<div>
<h3>组件B</h3>
<div>
<input type='text' value={value} onChange={this.onChildChange.bind(this)}/>
</div>
</div>
)
}
}
十、组合 vs 继承
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
包含关系:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left} </div>
<div className="SplitPane-right">
{props.right} </div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts /> }
right={
<Chat /> } />
);
}
特例关系:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children} </FancyBorder>
);
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}