组件
函数组件
1 2 3
| function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
|
“函数组件”本质上就是 JavaScript 函数
class组件
1 2 3 4 5
| class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
|
渲染组件
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性
(attributes)以及子组件
(children)转换为单个对象传递给组件,这个对象被称之为 “props
”。
例如,这段代码会在页面上渲染 “Hello, Sara”:
1 2 3 4 5 6 7
| function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
const root = ReactDOM.createRoot(document.getElementById('root')); const element = <Welcome name="Sara" />; root.render(element);
|
回顾一下这个例子中发生了什么:
- 调用
root.render()
函数,并传入 <Welcome name="Sara" />
作为参数。
- React 调用
Welcome
组件,并将 {name: 'Sara'}
作为props
传入。
- Welcome 组件将
<h1>Hello, Sara</h1>
元素作为返回值。
- React DOM 将 DOM 高效地更新为
<h1>Hello, Sara</h1>
。
注意: 组件名称必须以大写字母开头!!!
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div />
代表 HTML 的 div 标签,而 <Welcome />
则代表一个组件,并且需在作用域内使用 Welcome
。
组合组件
组件可以在其输出中引用其他组件
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
function App() { return ( <div> <Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div> ); }
|
提取组件
将组件拆分为更小的组件。
参考如下Comment
组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
|
该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中提取一些组件出来。
首先,我们将提取 Avatar
组件:
1 2 3 4 5 6 7 8
| function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); }
|
Avatar
不需知道它在 Comment
组件内部是如何渲染的。因此,我们给它的 props
起了一个更通用的名字:user
,而不是 author
。
我们建议从组件自身的角度
命名 props
,而不是依赖于调用组件的上下文命名。
我们现在针对 Comment
做些微小调整:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
|
接下来,将提取 UserInfo
组件,该组件在用户名旁渲染 Avatar
组件:
1 2 3 4 5 6 7 8 9
| function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); }
|
进一步简化 Comment
组件:
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
|
小总结:提取组件可能繁重,但值得
Props 的只读性
组件无论是使用函数声明还是通过 class 声明
,都绝不能
修改自身的 props
。
React 非常灵活,但它也有一个严格的规则:
所有 React
组件都必须像纯函数一样保护它们的 props
不被更改
组件通讯
父组件传递数据给子组件
- 1.父组件提供要传递的
state
数据
- 2.给子组件标签添加属性,值为
state
中的数据
- 3.子组件中通过
props
接收父组件中传递的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Parent extends React.Component{ state ={lastName:'王'} render(){ return( <div> 传递数据给子组件:<Child name={this.state.lastName}/> </div> ) } }
function Child(props){ return<div>子组件接收到数据:{props.name}</div> }
|
子组件传递数据给父组件
思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。
- 1.父组件提供一个回调函数(用于接收数据)
- 2.将该函数作为属性的值,传递给子组件
1 2 3 4 5 6 7 8 9 10 11 12
| class Parent extends React.Component{ getchildMsg = (msg)=>{ console.log('接收到子组件数据',msg) } render(){ return( <div> 子组件:<Child getMsg={this.getchildMsg}/> </div> ) } }
|
1 2 3 4 5 6 7 8 9 10 11
| class Child extends React.Component{ state ={childMsg:'React'} handleClick =()=>{ this.props.getMsg(this.state.childMsg) } render(){ return( <button onClick={this.handleClick}>点我,给父组件传递数据</button> ) } }
|
兄弟组件
- 将共享状态提升到最近的
公共父组件
中,由公共父组件管理这个状态
- 思想:
状态提升
- 公共父组件职责:
- 要通讯的子组件只需通过
pops接收
状态或操作
状态的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Counter extends React.Component{ state={ count:0 } onIncrement =()=>{ this.setstate({ count:this.state.count + 1 }) } render(){ return( <div> <Child1 count={this.state.count} /> <Child2 onIncrement={this.onIncrement} /> </div> ) } }
const child1=props =>{ return<h1>计数器:{props.count}</h1> } const child2=props =>{ return <button onClick={()=>props.onIncrement()}>+1</button> }
|