1、模块&组件
模块是指:
组件是指:结构样式交互全拆
比如某一个网页中的头部Header,可以将所有css、images、video等等文件一起复用。
2、类式组件初体验
无论是函数式组件还是类式组件,组件名的首字母都是大写
【注】:后期中函数式组件会使用更多
//类式组件只要调用一次,就相当于new 类名,创建了一个类组件实例化对象
//组件调用一次,相当于new一次,就会产生一个实例化对象
//调用:<组件名/>或者是<组件名><组件名/>
class MyComponent extends React.Component {
//类式组件中,render方法是必须要存在的,且返回一个虚拟DOM元素结构
//而其中的构造器函数,非必须要写,实在需要处理其类的实例化对象时才要加
constructor(){
//调用父类的constructor
super();
//this指向子类组件App的实例化对象
}
//render方法放在哪里? —— MyComponent的原型对象上,供实例化对象使用
//render中的this指向? —— MyComponent的实例化对象,即MyComponent组件的实例对象
render(){
return <p></p>
}
//1、React解析组件标签,找到了MyComponent组件;
//2、发现组件是使用类定义的,随后new出来该类的实例化对象,并通过实例对象调用原型身上的render方法;
//3、将render返回的虚拟DOM转换为真实DOM,随后呈现在页面上;
}
3、组件实例的三大核心属性
1》state属性
React 把组件看成是一个状态机(State Machines)。
如果在类中,想要将一些可以变化状态的数据存储到类的实例化对象之中,则需要将数据放在state。
React 里,通过更新组件的state来更新对应的页面显示,
只需更新组件的 state,然后根据新的 state 重新渲染用户界面。
State值是一个对象(可以包含多个key-value)
初始化state数据:类构造器中:this.state = {…} 类结构中: state={…}(更推荐!)
读取state数据: this.state.xxx
更新state数据: this.setState({…})
<div id="root"></div>
<script type="text/babel">
const root = ReactDOM.createRoot(document.querySelector('#root'));
let { Component, Fragment } = React;
class ChangeSun extends Component {
//constructor调用1次
//constructor中的this是组件实例化对象
constructor() {
super();
//this.state = { }
//方式三
//严格模式下,普通函数中的this指向undefined,修改this指向
this.changeSun2 = this.changeSun2.bind(this);
}
//设置状态值
//在实例化对象身上添加属性
state = {
isSunny: true;
}
//方式一
changeSun = () => {
let { isSunny } = this.state;
this.setState({
isSunny: !isSunny
})
}
//方式二
changeSun1() {
let { isSunny } = this.state;
this.setState({
isSunny: !isSunny
})
}
//方式三
//changeSun是作为onClick的回调,所以不是通过实例调用的,是直接调用的
//类中的方法,默认开启了严格模式,所以普通函数changeSun中的this指向undefined
//全局严格模式下的this丢失指向,不允许随意操作window对象,this为undefined。禁止自定义函数的this指向window
changeSun2() {
let { isSunny } = this.state;
this.setState({
isSunny: !isSunny
})
}
//render函数会调用几次?n+1次 第一次是初始化的那次,n表示的是状态更新的次数
//render中的this是组件实例化对象
render() {
let { isSunny } = this.state;
return (
<Fragment>
<h1>今天天气很{isSunny ? '晴朗' : '凉爽'}</h1>
<button onClick={this.changeSun}>切换天气—方式一</button>
<button onClick={() => { this.changeSun1() }}>切换天气—方式二</button><br />
<button onClick={this.changeSun2}>切换天气—方式三</button><br />
</Fragment>
)
}
}
root.render(<ChangeSun />)
</script>
2》Props属性:
每个组件对象都有Props属性,类式组件、函数组件都有Props属性,
Props是properties的缩写,如果想要在组件的外部向组件的内部传数据,那么就可以利用props
【知识点回顾——展开/扩展运算符】
…arr:可以展开一个数组
…obj:不能展开一个对象,语法错误
但如果使用babel语法转化为了JSX,就可以允许扩展运算符展开一个对象,但不允许随意使用,仅仅适用于标签中批量传递Props,也即批量传递标签属性。
(1)传递Props&批量传递Props
以key-value的形式传递,key={…}
//父组件
class Person extends Component {
render() {
let obj = {
uname: 'Evelyn',
uage: 22,
usex: '女'
}
return (
// <Student uname={obj.uname} uage={obj.uage} usex={obj.usex} />
//批量传递Props
//展开运算符本来是不能展开对象的
//由于babel转化文件,允许在Props传递数据时,展开对象
//通过...运算符来将对象的多个属性分别传入子组件
<Student {...obj} />
)
}
}
//子组件
class Student extends Component {
render() {
//解构
let { uname, uage, usex } = this.props;
return (
<ul>
<li>姓名:{uname}</li>
<li>年龄:{uage}</li>
<li>性别:{usex}</li>
</ul>
)
}
}
root.render(< Person />)
(2)限制Props类型 & 指定默认值
Props是只读属性,不允许改
Props在三大属性中,唯一一个,既可以在类中使用(this),又可以在函数中使用 (传参)!
3》refs属性
refs是虚拟DOM元素身上的属性名,可以用来标识将要获取的真实DOM。
refs是类式组件实例化对象身上的属性,用来获取真实的DOM元素对象。
函数式组件没有refs属性,但可以使用Hooks的useRef方法。
(1)Refs属性——字符串写法 (ref=" ")(官方最不推荐)
render() {
return <div>
用户名:<input type="text" ref="unameIpt" />
密 码:<input type="password" ref="upassIpt" />
<button onClick={() => { this.getFormValue() }}>获取表单元素值</button>
</div>
};
getFormValue() {
// console.log(this);
// 只有这种字符串方法,才会使用到this.refs的写法
// console.log(this.refs);
let uname_v = this.refs.unameIpt.value;
let upass_v = this.refs.upassIpt.value;
console.log(uname_v);
console.log(upass_v);
this.refs.unameIpt.value = '';
this.refs.upassIpt.value = '';
}
(2)Refs属性——回调函数写法
ref属性是虚拟DOM元素身上的一个属性名,目的是为了获取的真实DOM。
render() {
return <div>
用户名:<input type="text" ref={el => this.uname_ipt = el} />
密 码:<input type="password" ref={el => this.upass_ipt = el} />
<button onClick={this.getFormValue}>获取表单元素的值</button>
<div className={'box'} ref={el => this.box = el}></div>
</div>
}
getFormValue = () => {
let uname_v = this.uname_ipt.value;
let upass_v = this.upass_ipt.value;
let str = `用户名是:${uname_v}</br>密码是:${upass_v}`
this.box.innerHTML = str;
}
(3)Refs属性——React.createRef()写法
class GetFormValue extends React.Component {
//在类式组件实例化对象身上添加属性
unameIpt = React.createRef();//{current:null}
upassIpt = React.createRef();
box = React.createRef();
render() {
return <React.Fragment>
用户名:<input type="text" ref={this.unameIpt} /><br />
密 码:<input type="password" ref={this.upassIpt} /><br />
<button onClick={this.getFormValue}>获取表单元素值</button>
<div className={'box'} ref={this.box}></div>
</React.Fragment>
}
getFormValue = () => {
console.log(this);
let uname_v = this.unameIpt.current.value;
let upass_v = this.upassIpt.current.value;
let str = `用户名是${uname_v}</br>密码是${upass_v}`;
this.box.current.innerHTML = str;
}
}
4、非受控组件&受控组件
受控组件和非受控组件唯一的区别是,是否和状态值有关!
class Login extends Component {
unameIpt = React.createRef();
upassIpt = React.createRef();
//将表单元素中的值和状态值state绑定
state = {
uname: '',
upass: ''
}
changeName = () => {
this.setState({
uname: this.unameIpt.current.value
})
}
changePass = () => {
this.setState({
upass: this.upassIpt.current.value
})
}
show = () => {
console.log('用户名:', this.state.uname);
console.log('密码:', this.state.upass);
}
render() {
let { uname, upass } = this.state;
//双向绑定,通过属性值
return (
<Fragment>
<p>用户名:<input type="text" value={uname} onChange={this.changeName} ref={this.unameIpt} /></p>
<p>密 码:<input type="password" value={upass} onChange={this.changePass} ref={this.upassIpt} /></p>
<button onClick={this.show}>点击获取表单元素的值</button>
</Fragment>
)
}
}
5、案例优化——高阶函数
一个函数的实际参数 或 返回值是一个函数,则这样的函数就称为是一个高阶函数。
class Login extends Component {
unameIpt = React.createRef();
upassIpt = React.createRef();
//将表单元素中的值和状态值state绑定
state = {
uname: '',
upass: ''
}
//高阶函数,通过传参的方式
changeValue = (type) => {
//高阶函数的返回值是一个函数
return (ev) => {
this.setState({
[type]: ev.target.value
})
}
}
show = () => {
console.log('用户名:', this.state.uname);
console.log('密码:', this.state.upass);
}
render() {
let { uname, upass } = this.state;
//双向绑定,通过属性值
return (
<Fragment>
<p>用户名:<input type="text" value={uname} onChange={this.changeValue('uname')} ref={this.unameIpt} /></p>
<p>密 码:<input type="password" value={upass} onChange={this.changeValue('upass')} ref={this.upassIpt} /></p>
<button onClick={this.show}>点击获取表单元素的值</button>
</Fragment>
)
}
}