props
展开运算符
" … " 展开运算符可以和数组匹配使用
- 可以展开一个数组
let arr1 = [12,3,4]
console.log(...arr1)
let arr2 = [1,2,3,4]
- 也可以用于连接两个数组
let arr1 = [12,3,4]
let arr2 = [1,2,3,4]
let arr3 = [...arr1...arr2]
console.log(arr3)
- 传参
在函数中使用
function sum(...numbers) {
//numbers传进来一个数组
return numbers.reduce( (preValue,currentValue) => {
return preValue + currentValue;
})
}
- 构造字面量对象时使用展开语法
展开运算符不能展开一个对象,但是外面包上{},就可以复制一个对象
let person = {name:'Tome',age:'20'}
person2 = {...person}
5. 复制对象时合并属性
let person3 = {...person,name:'jack',address:'地球'}
批量传递props(批量传递标签属性)
<script type="text/babel">
//1. 创建组件
class Person extends React.Component {
render() {
const { name, age, sex } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
);
}
}
const p = { name: "TOME", sex: "male", age: "20" };
//渲染组件到页面
//babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
ReactDOM.render(<Person {...p} />, document.getElementById("test"));
</script>
对props进行限制
组件自身propTypes属性,可以进行类型的限制和必填限制。
组件自身的defaultProps属性,可以进行默认值的设置。
<script type="text/babel">
//1. 创建组件
class Person extends React.Component {
render() {
const { name, age, sex } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
);
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name: PropTypes.string.isRequired,//name设置必填,且为字符串
sex: PropTypes.string,//限制sex为字符串
age: PropTypes.number,//限制age为数字
};
//指定默认值
Person.defaultProps = {
sex: "male",//sex设置默认值
};
const p = { name: "TOME", sex: "male", age: "20" };
//渲染组件到页面
//babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
ReactDOM.render(<Person {...p} />, document.getElementById("test"));
</script>
props的简写
【!!props是只读的!!】
this.props.name = “TTome”//这行代码会报错
将限制属性写在类中,
添加到类对象上,在属性前加static
class Person extends React.Component {
render() {
const { name, age, sex } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
);
}
//对标签属性进行类型、必要性的限制
static propTypes = {
name: PropTypes.string.isRequired, //name设置必填,且为字符串
sex: PropTypes.string, //限制sex为字符串
age: PropTypes.number, //限制age为数字
};
//指定默认值
static defaultProps = {
sex: "male", //sex设置默认值
};
}
类式组件的构造器
构造器是否接收props,是否传递super,
取决于:是否希望在构造器中通过this访问props
不接收props,不传递super(props),this.props在构造函数中可能会出现未定义的bug
如果在构造函数中不通过this.props访问props,那写不写无所谓。
函数式组件使用props
函数式组件由于是函数,可以传递参数,可以使用props
function Person(props) {
console.log(props);
const { name, sex } = props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
</ul>
);
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name: PropTypes.string.isRequired, //name设置必填,且为字符串
sex: PropTypes.string, //限制sex为字符串
age: PropTypes.number, //限制age为数字
};
//指定默认值
Person.defaultProps = {
sex: "male", //sex设置默认值
};
const p = { name: "TOME", sex: "male", age: "20" };
//渲染组件到页面
//babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
ReactDOM.render(
<Person name="TOME" sex="male" />,
document.getElementById("test")
);
【不要把propTypes写成protoType了!!】
总结props
- 每个对象都会有props属性
- 组件标签的所有属性都保存在props中
- 通过标签属性从组件外向组件内传递变化的数据
- 组件内部不能修改props数据,props数据是只读的
refs
字符串形式的ref
已经不被推荐使用,效率不高,以后更新有可能直接废弃掉
class Demo extends React.Component {
showData = () => {
console.log(this.refs.input1);
const { input1 } = this.refs;
alert(input1.value);
};
showData2 = () => {
console.log(this.refs.input1);
const { input2 } = this.refs;
alert(input2.value);
};
render() {
return (
<div>
<input ref="input1" type="input" placeholder="点击按钮提示数据" />
<button ref="button1" onClick={this.showData}>
点击按钮提示左侧数据
</button>
<input
onBlur={this.showData2}
ref="input2"
type="input"
placeholder="失去焦点提示数据"
/>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"));
回调形式的ref
箭头函数没有this,this向外找,找到了组件实例对象。
ref={© => (this.input1 = c)}这个回调函数的调用者是当前节点,不是我们自己调用传参,所以c接收当前节点,并且把这个节点放在实例对象的input1属性上
<script type="text/babel">
class Demo extends React.Component {
showData = () => {
const { input1 } = this;
alert(input1.value);
};
showData2 = () => {
const { input2 } = this;
alert(input2.value);
};
render() {
return (
<div>
<input
ref={(c) => (this.input1 = c)}
type="text"
placeholder="点击按钮提示数据"
/>
<button onClick={this.showData}>点击按钮提示左侧数据</button>
<input
onBlur={this.showData2}
ref={(c) => (this.input2 = c)}
type="text"
placeholder="失去焦点提示数据"
/>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"));
</script>
回调函数中ref调用次数的问题
- 如果ref回调函数是以内联函数的方式定义的,在更新过程中会被执行两次,第一次传入的参数是null,第二次传入的参数才是节点。
- 这是因为在每次渲染时会创建要给新的函数实例,所以React清空旧的ref并且设置新的
- 通过将ref回调函数定义成class的绑定函数的方式可以避免上述问题,但是大多数情况下这是无关紧要的。
<script type="text/babel">
class Demo extends React.Component {
state = { isHot: false };
showInfo = () => {
const { input1, btn } = this;
alert(input1.value);
};
changeWeather = () => {
const { isHot } = this.state;
this.setState({ isHot: !isHot });
};
saveInput = (c) => {
this.input1 = c;
console.log("@", c);
};
render() {
const { isHot } = this.state;
return (
<div>
<h2>今天天气很 {isHot ? "炎热" : "凉爽"}</h2>
{/*<input
ref={(c) => {
console.log("@",c);
this.input1 = c;
}}
type="text"
/>*/}
{/*内联形式回调ref*/}
<input ref={this.saveInput} type="text" />
{/*类绑定形式定义ref*/}
<br />
<br />
<button ref={(c) => (this.btn = c)} onClick={this.showInfo}>
点我提示输入的数据
</button>
<button onClick={this.changeWeather}>点我改变天气</button>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"));
</script>
createRef
- React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
- 该容器是专人专用的,一个容器只能存一个
- 用几个ref就得创建几个容器
- 有点麻烦,但是这种方式是目前react最推荐使用的
<script type="text/babel">
myRef = React.createRef();
myRef2 = React.createRef();
class Demo extends React.Component {
showData = () => {
const { input1 } = this.myRef.current;
alert(input1.value);
};
showData2 = () => {
const { input2 } = this.myRef2.current;
alert(input2.value);
};
render() {
return (
<div>
<input
ref={this.myRef}
type="text"
placeholder="点击按钮提示数据"
/>
<button onClick={this.showData}>点击按钮提示左侧数据</button>
<input
onBlur={this.shoData2}
ref={this.myRef2}
type="text"
placeholder="失去焦点提示数据"
/>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"));
</script>