React笔记03:props、组件通讯、非受控组件
非受控组件(了解)
- 借助于 ref 就可以通过 非受控组件 的方式,来获取到的表单元素的值。
- ref 的作用:获取DOM对象或组件。
import React from 'react';
import ReactDOM from 'react-dom';
class Hello extends React.Component{
constructor(){
super();
//1.创建ref
this.txtRef = React.createRef();
}
handleClick = ()=>{
//3.通过this.txtRef.current使用
console.log(this.txtRef.current.value);
}
render(){
return (
<div>
{/* 2.绑定ref */}
<input text="text" ref={this.txtRef}/>
<button type="button" onClick={this.handleClick}>取值</button>
</div>
)
}
}
ReactDOM.render(<Hello></Hello>,document.getElementById("root"));
props的使用
- 作用:接收到传递给组件中的属性
- 在函数组件中如何获取到 props? 通过函数的参数
- 在 类组件 中如何获取到 props? 通过 this.props 来获取
- props 是一个对象!!!
- 特点:只读!!!( 只能读取 props 对象中的属性,而不能修改 props 对象中的属性 )
- 可以给组件传递任何类型的数据。
- 注意:如果在 class 组件中,手动添加了 constructor ,那么,就应该通过参数获取到 props, 然后传递给 super,这样,才能够在 constructor 中,获取到 props!!!
//函数组件
const Hello = props => {
// props 就表示传递给组件的属性
console.log(props);
}
//给组件传参数
<Hello name="jack" age={19} colors={['red','blue','green']} />
// 类组件:
class Hello extends React.Component {
constructor(props) {
super(props)
// console.log('在构造函数中,获取到 props ', this.props)
console.log('在构造函数中,获取到 props ', props)
}
render() {
console.log('class组件中获取到props:', this.props)
return (
<div>
<h1>props:{this.props.age}</h1>
{this.props.colors.map((item, index) => (
<p key={index}>{item}</p>
))}
</div>
)
}
}
组件通讯
父到子
- 1 父组件中提供状态
- 2 在子组件标签上添加属性,值为 父组件中的状态
- 3 子组件中通过 props 来接收父组件中传递过来的数据
// 父组件:
class Parent extends React.Component {
// 提供数据
state = {
lastName: '王'
}
render() {
return (
<div className="parent">
<h1>父组件:</h1>
{/* 1 通过属性给子组件传递数据 */}
<Child name={this.state.lastName} />
</div>
)
}
}
// 子组件:
// 2 子组件中通过 props 接收数据
const Child = props => {
return <p className="child">这是子组件:{props.name}</p>
}
子到父
思路:父组件提供一个事件(函数),让子组件调用;子组件调用的时候,将数据作为参数的传递,父组件中通过事件(函数)的参数,就拿到子组件中的数据了。
1 父组件提供事件
2 将事件通过props传递给子组件
3 子组件中通过props接收到父组件中传递过来的事件
4 子组件调用该事件,将数据作为参数传递
注意点:父组件提供的方法中 this 执行问题。
- 为什么会有这个问题?因为这个方法不是父组件自己调用的,是由其他组件调用的,所以,需要处理this指向。
// 1 提供事件(回调函数,)
// 事件是子组件调用的,因此,先要通过 props 传递给子组件
// 2 将事件传递给子组件
class Parent extends React.Component {
state = {
msg: ''
}
getChildMsg = data => {
console.log('父组件中的方法调用了', data)
this.setState({
msg: data
})
}
// 注意:this指向问题,因为这个方法是由子组件调用的,所以,应该提前处理好 this 指向!
/* getChildMsg(data) {
console.log('父组件中的方法调用了', data, this)
this.setState({
msg: data
})
} */
render() {
return (
<div className="parent">
<h1>父组件:{this.state.msg}</h1>
<Child fn={this.getChildMsg} />
</div>
)
}
}
// 子组件:
// 3 子组件中通过 props 接收到父组件中传递过来的事件
// 4 子组件中调用传递过来的事件, 将数据作为事件的参数传递
const Child = props => {
// console.log(props)
const handleClick = () => {
// 调用
props.fn('撩汉子')
}
return (
<p className="child">
这是子组件:
<button onClick={handleClick}>发送数据给父组件</button>
</p>
)
}
兄弟组件
- 思路:状态提升,也就是:将两个兄弟组件之间的共享数据,放在父组件中。
- 父组件的职责:1 提供共享数据(state) 2 提供修改状态的方法
- 例子:如果 子组件2 要传递数据给 子组件1
- 子组件1:只要通过 props 接收到父组件中传递过来的数据(父 -> 子)
- 子组件2:调用父组件中修改状态的方法(子 -> 父)
- 但是,需要先通过 props 获取到父组件中传递过来的方法
// 父组件
// 1 提供状态
// 2 提供操作状态的方法
class Parent extends React.Component {
state = {
msg: '默认值'
}
updateMsg = data => {
this.setState({
msg: data
})
}
render() {
return (
<div className="parent">
这是父组件:
<Child1 msg={this.state.msg} />
<Child2 updateMsg={this.updateMsg} />
</div>
)
}
}
// 子组件1
// 3 接收数据(数据由父组件提供)
class Child1 extends React.Component {
render() {
return <div className="child">这是子组件1:{this.props.msg}</div>
}
}
// 子组件2:
// 4 在父组件中传递事件给子组件
// 5 给按钮绑定单击事件
// 6 调用父组件中的事件来更新数据
class Child2 extends React.Component {
// 单击事件
handleClick = () => {
// 调用父组件的事件
this.props.updateMsg('子组件2222222222222222222222')
}
render() {
return (
<div className="child2">
这是子组件2:
<button onClick={this.handleClick}>传递数据给 Child1</button>
</div>
)
}
}
评论列表案例
分析:因为 CommentList 和 CommentForm 这两个子组件中,都要用到 评论列表 数据,所以,就利用 状态提升 的思想,将评论列表数据放在了 父组件Comment 中。
- 父组件的两个职责:1 提供评论列表数据状态(list) 2 提供修改状态的方法(updateComment)
功能1:渲染评论列表
- 利用 父->子 的通讯,将父组件中的 list 传递给 子组件;子组件中通过 props 接收
// 父组件中渲染子组件:
<CommentList list={this.state.list} />
// 子组件中:
<ul>
{props.list.map(item => (
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>
- 功能2:添加评论
- a. 通过受控组件的方式,来获取到评论人和评论内容
- b. 将用户输入的内容,添加到 list 中
- 因为 list 是由父组件提供的,所以,由父组件提供修改状态的方法(updateComment);通过 props 传递给子组件后,由子组件调用
// 父组件中渲染子组件:
<CommentForm updateComment={this.updateComment} />
// 子组件中:
// 发表评论
addComment = () => {
const { name, content } = this.state
// ...
this.props.updateComment(name, content)
// ...
}
Context(了解)
- 使用场景:跨组件传递数据
- 如果两个组件是远方亲戚(比如,嵌套多层)可以使用Context实现组件通讯
- Context提供了两个组件:Provider 和 Consumer
- Provider组件:用来提供数据
- Consumer组件:用来消费数据
const { Provider, Consumer } = React.createContext()
<Provider value={this.state.msg}>
<div className="parent">
这是父组件:
<Child1 />
</div>
</Provider>
// Child1 -> Child2 -> Child3
// Child3
// data 就是 Provider 中提供的 value
<Consumer>{data => <p>接收到的数据为:{data}</p>}</Consumer>
组件的 children 属性
- 作用:获取组件标签的子节点
- 获取方式: props.children
- children 与普通的 props 属性相同,可以是任意值。
class Parent extends React.Component{
render(){
return (
<div>
<Child>哈哈</Child>
<Child>{11}</Child>
<Child>{["red","blue","green"]}</Child>
</div>
)
}
}
class Child extends React.Component{
render(){
// 获取children中的值
console.log(this.props.children);
return (
<div>
子节点
</div>
)
}
}
props 校验
场景:给组件添加 props 校验,来增强组件的健壮性。
- 约定:封装公共组件的时候,都添加 props 校验
1 安装:
yarn add prop-types
2 导入
import PropTypes from 'prop-types'
3 给组件名称添加
propTypes
属性,值是一个对象4 对象的键就是要校验的 props 名称,值是
PropTypes.array
等,从PropTypes中获取到的校验规则
const Parent = () => { ... }
// 2 给组件添加 props 校验
Parent.propTypes = {
// 规定 colors 属性的类型为:数组(array),如果将来使用组件的时候,传入的 colors 属性类型不是 array ,就会通过警告来告诉使用者。
colors: PropTypes.array,
gender: PropTypes.oneOf(['male', 'female']).isRequired
}
props 默认值
- 可以通过 组件名.defaultProps = {} 来给组件添加 props 的默认值。
const Parent = () => { ... }
// 添加 props 的默认值:
Parent.defaultProps = {
gender: 'male'
}
赞 (0)