Props介绍与应用
什么是 props
props
可以看成一个对外的接口,用来接收外部传入的数据。组件中主要有两种属性 props
和 state
无论 props 或者 state 中哪两个发生了改变都会重新引发渲染
如何使用
如果你使用过 Vue,也肯定使用过父传子和子传父的功能,在 react 中也有父子通信。
父传子
函数组件
上一篇文章我讲述了使用[...props]
来进行传值,那是一种简写。
// 父组件
function Component1(){
// 创建一个ref
const porps = {name: 'ccc',age:18};
const a = {h: 'ccc'};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<User {...porps} /> {/* 使用简写 */}
<User name='我没有用简写' age='18' />
{/* 如果是非字符串 就要用大括号*/}
<User name='我没有用简写' age='18' title={a}/>
</div>
);
}
// 通过参数去接受值
function User(props){
return(
<div>
<h2>我是user组件</h2>
<p>{props.name}---{props.age}</p>
</div>
);
}
上面的代码中就是简写和非简写的区别。可以直接在组件编写属性的方式传参数,在用 props
去接收参数。
我们都知道react在没有 hook
之前他们两个的区别主要在于有无 state
和生命周期,类组件可以使用生命周期和构造函数,而函数组件中只有 props
,函数组件也称为无状态组件。类组件如果有 state
就是有状态组件,没有 state
就是无状态组件。如果类组件没有 state
推荐使用函数组件(函数组件效率高于类组件)。有了 hook
之后 在函数组件组件里面也可以使用 state
。
类组件
类组件中如何传值
// 定义一个函数组件和写内联样式
// 父组件
function Component1(){
// 创建一个ref
const porps = {name: 'ccc',age:18};
const a = {h: 'ccc'};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<User {...porps} /> {/* 使用简写 */}
<User name='我没有用简写' age='18' />
{/* 如果是非字符串 就要用大括号*/}
<User name='我没有用简写' age='18' title={a}/>
</div>
);
}
// 类组件 props 被实例化了 可以直接使用this.去访问之后在结构
class Footer extends React.Component {
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{name}---{age}</h1>
</div>
);
}
}
默认值
可以通过 defaultProps
设置默认值
// 父组件
function Component1(){
// 创建一个ref
const porps = {name: 'ccc',age:18};
const a = {h: 'ccc'};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<User/>
{/* 如果是非字符串 就要用大括号*/}
<User name='我没有用简写' age='18' title={a}/>
</div>
);
}
// 子组件
function User(props){
return(
<div>
<h2>我是user组件</h2>
<p>{props.name}---{props.age}</p>
</div>
);
}
User.defaultProps = {
age: 20,
name: 'xxx'
};
子传父
props 可以接受任意类型的值。我们可以利用这个特性来实现子组件到父组件的传值,我们可以传递一个函数,通过函数传参的方式,来实现这一功能。这里使用的 this 绑定方式这里查看介绍
// 父组件
function Component1(){
// 创建一个ref
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
function getData(data){
console.log('我是接受接受到子组件的值', data);
}
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} getData={getData} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt',
num: 0
};
}
add = () => {
this.setState(state =>({
num: ++state.num,
}));
this.props.getData(this.state.num);
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
<button onClick={this.add}>点我加一{this.state.num}</button>
</div>
);
}
}
修改 props
在 React 中我们不能直接修改 props
// 子组件
function User(props){
props.name = 'ttt';
return(
<div>
<h2>我是user组件</h2>
<p>{props.name}---{props.age}</p>
</div>
);
}
// 第三行报错
上面的代码会报错,props 是个只读属性。在 react 中数据流是单向的,不能改变一个组件在渲染是传进来的 props
。因为组件会复用,如果可以修改 props,结果会不可预测,也违背了组件的设计原则,但是这并不代表在 props 不能修改**。**
可以通过 state
来变相修改 props
。state 可以理解为中间人,主要是利用了 react 里面的重新渲染(setState)方式把props传入到组件中,在通过赋值到 state,在来修改。
// 父组件
function Component1(){
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
// constructor是构造器函数,如果没有申明,会自动添加,而且只会执行一次
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt'
}
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
</div>
);
}
}
constructor 里面除了修改 props 还可以进行函数绑定
// 父组件
function Component1(){
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt',
num: 0
};
this.add = this.add.bind(this);
}
add(){
this.setState(state =>({
num: ++state.num,
}));
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
<button onClick={this.add}>点我加一{this.state.num}</button>
</div>
);
}
}
事件监听 this 绑定
this 一共有四种绑定方式,一种就是我上面说的在 constructor
使用 bind
绑定。而且这种方法也是官方推荐的。
下面我来介绍其他三种
直接在 jsx 元素上进行绑定(不推荐)
// 父组件
function Component1(){
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt',
num: 0
};
}
add(){
this.setState(state =>({
num: ++state.num,
}));
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
<button onClick={this.add.bind(this)}>点我加一{this.state.num}</button>
</div>
);
}
}
上面代码中我们直接在 button
上进行了绑定。但是这样子会出现一个问题,就是每次在渲染组件的时候,都会创建一个新的函数。会造成额外的渲染,影响性能。
箭头函数(推荐)
使用了 ES6 的类字段
// 父组件
function Component1(){
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt',
num: 0
};
}
add = () => {
this.setState(state =>({
num: ++state.num,
}));
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
<button onClick={this.add}>点我加一{this.state.num}</button>
</div>
);
}
}
因为箭头函数本身没有 this 属性,所以他的 this 指向的是 Footer 这个类本身,这个方法是推荐的因为不会存在多重绑定的问题。
直接在 jsx 上使用箭头函数(不推荐)
// 父组件
function Component1(){
const userRef = React.createRef();
const porps = {name: 'ccc',age:18};
return (
<div style={divStyles} title={divTitles} className="App" tab-index="1">
<Footer {...porps} ref={userRef}></Footer>
</div>
);
}
// 子组件
class Footer extends React.Component {
constructor(props){
super(props);
// 组件内部的状态 通过 setState 方法来更改的
this.state = {
name1:props.name+'ttt',
num: 0
};
}
add = () => {
this.setState(state =>({
num: ++state.num,
}));
}
render() {
const {name,age} =this.props;
return(
<div>
<h1>我是一个类组件{this.state.name1}---{age}</h1>
<button onClick={() => {
this.setState(state =>({
num: ++state.num,
}));
}}>点我加一{this.state.num}</button>
</div>
);
}
}
直接在 jsx 上使用箭头函数会导致和直接在 jsx 上进行绑定一样的问题就是每次在渲染组件的时候,都会创建一个新的函数。会造成额外的渲染,影响性能。事件只要是在 render
上绑定事件都会出现性能问题。
