一.无状态组件
顾名思义就是组件内部没有(不需要)state,无状态组件也可以理解为展示组件,仅做展示用,可以根据外部传来的props来渲染模板的内容,内部没有数据。
//无状态组件:组件内部没有state,可以使用函数式组件。它只负责展示
let Book = (props) => (
<div>
<p>书名:{props.name}</p>
<p>作者:{props.author}</p>
</div>
);
仅仅只是一个函数,就ok了。
二.有状态组件
有状态组件就是不但外部可以传入,内部也有state。
有状态组件也可以理解为容器组件,用来容纳展示组件,在容器组件里处理数据的逻辑,把结果在展示组件里呈现。
创建有状态组件如下:
// 有状态组件:有state,负责数据的处理。
class Books extends React.Component {//容器组件
constructor(props) {
super();
this.state = {
bookList: [
{
name: "三国",
author: "罗贯中",
},
{
name: "哆啦A梦",
author: "哈哈哈",
},
{
name: "皮卡丘",
author: "xixi",
},
],
};
}
render() {
return(
<div>
<h1>书籍列表</h1>
<ul>
{/*Book为展示组件*/}
{this.state.bookList.map((item,index) => (
<Book name={item.name} author={item.author} key={index}/>
))}
</ul>
</div>
);
}
}
ReactDOM.render(
<div>
<Books />
</div>,
document.getElementById("box")
);
注意:
做项目时,经常会把有状态组件和无状态组件进行结合使用。
1)、 有状态组件:一般会使用类组件,处理数据的业务逻辑,包括和后端进行交互,获取数据。把数据传给无状态组件
2)、 无状态组件:一般会使用函数式组件,只做展示用,没有自己的数据,会接收有状态组件传来的数据。
三. 事件处理
3.1事件特点:
1、React 事件绑定属性的命名采用驼峰式写法,而不是小写。如:onClick。
2、如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
3、在 React 中另一个不同的是,不能使用return false 的方式阻止默认行为, 你必须使用 preventDefault。
4、事件处理函数里的this是undefined(啊………),如果希望事件处理函数里的this是React组件对象本身,则需要用bind。
3.2 事件语法
3.2.1格式
<JSX元素 onClick={this.实例方法|函数体} />
示例:
class Books extends React.Component {
constructor(props) {
super();
}
fn(){
console.log("点击了~");
}
render() {
return(
<div>
<input type="button" value="测试" onClick={this.fn}/>
</div>
);
}
}
ReactDOM.render(
<div>
<Books />
</div>,
document.getElementById("box")
);
重点来袭~
3.2.2事件处理函数里的this
事件处理函数里的this是undefined,如何让事件处理函数里的this是React组件对象本身
- 使用bind
1)、构造器(构造函数)里:this.方法=this.方法.bind(this)
2)、在事件绑定时写,onClick={this.方法.bind(this)}
class Books extends React.Component {
constructor(props) {
super();
// 1、使用bind,让事件处理函数了的this是react组件对象。bind不会调用函数,会绑定该函数,返回一个新的函数。
// this.fn02 = this.fn01.bind(this);
this.fn01=this.fn01.bind(this);
}
fn01(){
console.log("点击了~");
console.log("this",this);
}
render() {
return(
<div>
<input type="button" value="测试01" onClick={this.fn01}/>
{/*直接使用bind*/}
<input type="button" value="测试02" onClick={this.fn01.bind(this)}/>
</div>
);
}
}
ReactDOM.render(
<div>
<Books />
</div>,
document.getElementById("box")
);
- 使用箭头函数 1)、事件绑定时,使用箭头函数:onClick={()=>this.方法()}
class Books extends React.Component {
constructor(props) {
super();
fn01(){
console.log("点击了~");
console.log("this",this);
}
render() {
return (
<div>
<input type="button" value="测试03" onClick={()=>this.fn01()}/>
</div>
);
}
}
ReactDOM.render(
<div>
<Books />
</div>,
document.getElementById("box")
);
2)、定义方法时,直接使用箭头函数: 方法=()=>{箭头函数定义方法}
class Books extends React.Component {
constructor(props) {
super();
// 4、定义方法时,使用箭头函数
fn04 = () => {
console.log("点击了~");
console.log("this", this);
};
render() {
return (
<div>
<input type="button" value="测试04" onClick={this.fn04} />
</div>
);
}
}
ReactDOM.render(
<div>
<Books />
</div>,
document.getElementById("box")
);
3.2.3事件对象
event对象是经过react处理过的。
如何获取事件对象------直接声明即可。
实例方法(ev) ev 代理事件对象 ,ev.target 返回虚拟Vdom
事件对象的获取:
1)、直接声明(没有其它参数的情况下)
//无其他参数
fn01 = (ev) => {
console.log("ev", ev);
// 真实DOM
console.log("ev.target", ev.target);
};
<input type="button" value="测试01" onClick={this.fn01} />
2)、箭头函数里直接声明(有其它参数的情况下)
// 有其他参数
// 注意:这已经不是事件处理函数了
fn02 = (ev, str) => {
console.log("ev", ev);
console.log("ev.target", ev.target);
console.log("str", str);
console.log("this", this);
};
//注意:给onClick绑定的函数,还是只有一个参数,这个参数就是事件对象,此处在绑定的函数里再调用另外一个函数进行传参
<input
type="button"
value="测试02"
onClick={(ev) => this.fn02(ev, "hi")}
/>
注意:给事件属性绑定的函数,永远只会有一个参数,该参数就是事件对象。
3.2.4阻止浏览器的默认行为:
只能用preventDefault,不能在事件函数里使用return false。
原封不懂得输入到大脑就好啦~简单!
四.组件的内容 :children
组件的内容,使用 children属性获取
class Books extends React.Component {
constructor(props) {
super();
}
render() {
return (
<div>
<p>我是上面的片</p>
{this.props.children}
<p>我是下面的片</p>
</div>
);
}
}
ReactDOM.render(
<div>
<Books>
<h1>我是组件之间的内容</h1>
</Books>
</div>,
document.getElementById("box")
);
五.refs
5.1获取DOM
表示对组件真正实例(也就是html标签,也就是DOM对象)的引用,其实就是ReactDOM.render()返回的组件实例;ref可以写在html标签里,也可以写在组件(自定义标签里),和vue的ref是同样的意思。
官方建议: 勿过度使用 Refs(尽量不要操作DOM),在对逻辑进行处理的时候尽量优先考虑state(数据驱动)
5.2用法
1). 赋值为 字符串(官方不推荐使用)
class Books extends React.Component {
constructor(props) {
super();
}
fn01 = () => {
this.refs.username.value = "hhh";
};
render() {
return (
<div>
{/*赋值为字符串*/}
<input type="text" ref="username" />
<input type="button" value="测试01" onClick={this.fn01} /><br/>
</div>
);
}
}
ReactDOM.render(
<div>
<Books></Books>
</div>,
document.getElementById("box")
);
2). 赋值为 回调函数
当给 HTML 元素添加 ref 属性时,ref 回调接收了底层的 DOM 元素作为参数。
ref 回调会在componentDidMount 或 componentDidUpdate 这些生命周期回调之前执行。
//ref的值赋成回调函数时,回调的参数就是当前dom元素。 // callback refs 回调 <jsx ref={el => this.定义一个实例属性 = el} //el就是dom对象 this.定义一个实例属性 //后期用作访问jsx元素 //当组件挂载时,将 DOM el元素传递给 ref 的回调 //当组件卸载时,则会传递 null。 //ref 回调会在 componentDidMount 和 componentDidUpdate 生命周期之前调用 如: <input type="text" ref={(currDom) => this.input1 = currDom} /> <input type="text" ref={(currDom) => this.input2 = currDom} />
class Books extends React.Component {
constructor(props) {
super();
this.ipt=null;
}
fn02=()=>{
this.ipt.value = "啦啦啦";
}
render() {
return (
<div>
<input type="text" ref={el=>this.ipt=el}/>
<input type="button" value="测试02" onClick={this.fn02}/>
</div>
);
}
}
ReactDOM.render(
<div>
<Books></Books>
</div>,
document.getElementById("box")
);
3). React.createRef() (React16.3提供)
使用此方法来创建ref。将其赋值给一个变量,通过ref挂载在dom节点或组件上,该ref的current属性将能拿到dom节点或组件的实例。
//1、在构造函数里 // 实例化 this.firstRef = React.createRef() //发生在构造器 //2、挂载在ref属性上 //3、获取dom原始 this.firstRef.current //current是官方的属性
class Books extends React.Component {
constructor(props) {
super();
this.firstRef = React.createRef(); //发生在构造器
}
fn03=()=>{
console.log(this.firstRef.current);
}
render() {
return (
<div>
{/* React.createRef() (React16.3提供) */}
<input type="text" ref={this.firstRef} />
<input type="button" value="测试03" onClick={this.fn03} />
</div>
);
}
}
ReactDOM.render(
<div>
<Books></Books>
</div>,
document.getElementById("box")
);