一.React 组件的两种创建方式
1.使用函数创建组件
- 使用 JS 中的函数创建的组件叫做: 函数组件
- 函数组件必须有返回值
- 组件名称必须以大写字母开头,React 据此区分组件和普通的React 元素
- 使用函数名作为组件标签名
// 函数组件
// 第一种
// function Hello(){
// return (
// <div>react组件</div>
// )
// }
// 第二种 必须要有返回值
// function Hello(){
// return null;
// }
// 第三种
const Bac = () => (
<div>
<ul>
{list.map((item) => <li key={item.id}>{item.name}</li>)}
</ul>
</div>
)
const Hello = () => <div>我是react的函数组件</div>
ReactDOM.render(<Hello />,document.getElementById('root'))
2.使用类创建组件
- 类组件: 使用 ES6 的 class 创建的组件
- 类名称必须以大写字母开头
- 类组件应该继承 React.Component 父类,从而可以使用父类中提供的方法或属性
- 类组件必须提供 render() 方法
- render() 方法必须有返回值,表示该组件的结构
// 类创建组件
class Hello extends React.Component {
render() {
return (
<div>我是React的类组件</div>
)
}
}
// 渲染组件
ReactDOM.render(<Hello />,document.getElementById('root'));
3.我们可以把组件抽离为独立JS文件
步骤:
- 创建 Hello.js
- 在 Hello.js 中导入 React
- 创建组件(函数组件 或者 类组件)
- 在 Hello.js 中导出该组件
- 在 index.js 中导入 Hello 组件
- 渲染组件
// Hello.js
import React from 'react';
class Hello extends React.Component {
render() {
return (
<div>我是抽离出来的Hello.js</div>
)
}
}
export default Hello;
// index.js
import Hello from './Hello.js';
const root = document.getElementById('root');
// 渲染组件
ReactDOM.render(<Hello />,root);
二.React 事件处理
1.事件绑定
- React 事件绑定语法 与 DOM 事件语法相似
- 语法: on+事件名称={事件处理程序}
- 注意点: React 事件采用驼峰命名法,如: onClick,onFocus
const root = document.getElementById('root');
class Hello extends React.Component {
handlerClick(){
console.log('触发了点击事件')
}
render(){
return (
// <button onClick={this.handlerClick}>点击事件</button>
<button onClick={()=>alert('111111111111')}>点击事件</button>
)
}
}
// 渲染组件
ReactDOM.render(<Hello />,root);
2.事件处理
- 可以通过事件处理程序的参数获取到事件对象
- React 中的事件对象叫做: 合成事件(对象)
- 合成事件: 兼容所有浏览器,无需担心跨浏览器兼容性问题
const root = document.getElementById('root');
class Hello extends React.Component {
handlerClick(e) {
// 阻止浏览器的默认行为
e.preventDefault();
console.log('触发了点击事件')
}
render() {
return (
// <button onClick={this.handlerClick}>点击事件</button>
<div>
<button onClick={() => alert('11111111')}>点击事件</button>
<a href="https://react.docschina.org/docs/components-and-props.html" onClick={this.handlerClick}>react</a>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<Hello />, root);
三.有状态组件(函数组件)和无状态组件(类组件)
- 函数组件又叫做无状态组件,也就是它没有自己的状态,只负责数据显示
- 类组件叫做有状态组件,就是有状态组件,它可以对数据进行更新
1.组件中的 state 和 setState
- state 的基本使用和获取
- 状态即是数据(state),它是组件内部私有的数据,只能在组件内部使用
- state 的值是对象,表示一个组件中可以有多个数据
- 可以通过 this.state 来获取状态
// 第一种方式
class Comp extends React.Component {
constructor(){
super()
// 初始化 state
this.state = {
count:0
}
}
render() {
return (
<div>
<li>{this.state.count}</li>
<div>有状态组件</div>
</div>
)
}
}
第二种方式
class Comp extends React.Component {
// 简化写法
state = {
count:0
}
render() {
return (
<div>
<li>{this.state.count}</li>
<div>有状态组件</div>
</div>
)
}
}
- 修改state的数据
- 语法: this.setState({要修改的数据})
- 注意:不可以直接修改 state 中的值,这是错误的
- setState({}) 的作用:修改 state,更新视图
// 正确修改 state 中的数据
this.setState({
count:this.state.count + 1
})
// 错误修改 state 中的数据
this.state.count += 1
2.事件绑定 this 指向
- 箭头函数
- 利用箭头函数自身没有this的特点
- render() 方法中的this为组件实例可以获取到 setState()
class Hll extends React.Component {
handlerClick(e) {
// 阻止浏览器的默认行为
e.preventDefault();
console.log('触发了点击事件')
}
state = {
count:2
}
// 事件处理程序
onIncrement(){
this.setState({count:this.state.count + 10})
console.log(this)
}
render() {
// 箭头函数中的this指向外部环境,此处为: render()
return (
// <button onClick={this.handlerClick}>点击事件</button>
<div>
<div>{this.state.count}</div>
<button onClick={()=> this.onIncrement()}>点击+10</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render([<Hello />,<Hll />], root);
- class 的实例方法(推荐)
- 利用箭头函数形式的class实例方法
- 由于babel的存在可以直接使用
class Hll extends React.Component {
state = {
count: 0
}
// 事件处理程序 class实例方法用箭头函数
onIncrement = () => {
console.log(this)
this.setState({count: this.state.count + 10})
}
render() {
return (
<div>
<h2>{this.state.count}</h2>
<button onClick={this.onIncrement}>点击+10</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render([<Hello />,<Hll />], root);
3.表单处理
- 受控组件的概念
- React中可变状态通常保存在 state 中,并且只能通过 setState() 方法来修改
- React将state与表单元素值value绑定到一起,由 state 的值来控制表单元素的值
<input type="text" value={this.state.count}
onChange={e => this.setState({count:e.target.value})}
/>
- 受控组件的使用步骤
1.在 state 中添加一个状态,作为表单元素的value值
state = {
count: 0
}
2.给表单元素绑定 change 事件,将表单元素的值设置为 state 的值 (控制表单元素值的变化)
<input type="text" value={this.state.count}
onChange={e => this.setState({count:e.target.value})}
/>
4.非受控组件
使用步骤:
- 调用 React.createRef() 方法创建一个 ref 对象
constructor(){
super()
this.txtRef = React.createRef()
}
- 将创建好的 ref 对象添加到文本框中
- 通过 ref 对象获取到文本框的值
注意点:表单数据由DOM本身处理。即不受setState()的控制
四.组件的props
- 组件是封闭的,要接收外部数据应该通过 props 来实现
- props 的作用: 接收传递给组件的数据
- 接收数据:注意:函数组件通过参数 props 接收数据,类组件通过 this.props 接收数据
<Hello2 name='张三' age={20} tag={<h1>呵呵呵呵</h1>} />
function Hello2(props) {
console.log(props)
return (
<div>接收到数据:{props.name}</div> // 张三
)
}
class Hello2 extends React.Component {
render() {
return (
<div>
{this.props.age} // 20
</div>
)
}
}
props 的特点:
- props 是只读的对象,只能读取属性的值,无法修改对象
- 注意点:如果使用类组件时,写了构造函数,应该将 props 传递给 super() ,否则,无法在构造函数中获取到props
class Hello extends React.Component {
constructor(props){
// 推荐将 props 传递给父类构造函数
super(props)
}
render() {
return (
<div>
{this.props.age}
</div>
)
}
}
1.父组件传递数据给子组件
- 父组件提供要传递的state数据
- 给子组件标签添加属性,值为 state 中的数据
- 子组件中通过 props 接收父组件中传递的数据
// 父传子
class Parent extends React.Component {
state = {
lastName: '小明'
}
render() {
return (
<div>
父组件向子组件传递数据 <Child name={this.state.lastName} />
</div>
)
}
}
function Child(props) {
console.log(props)
return (
<div>
<h1>子组件接收父组件数据: {props.lastName}</h1>
</div>
)
}
ReactDOM.render(
[<Parent />],
document.getElementById('root'),
()=> console.log('渲染成功')
);
2.子组件传递数据给父组件
- 父组件提供一个回调函数(用于接收数据)
- 将该函数作为属性的值,传递给子组件
- 子组件通过 props 调用回调函数
- 将子组件的数据作为参数传递给回调函数
// 子传父
// 父组件
class Parents extends React.Component {
state = {
lastName:''
}
// 调用回调函数用来接收数据
handlers = (data) => {
console.log('子组件向父组件传递的数据:',data)
this.setState({
lastName:data
})
}
render() {
return (
<div>
<h1>父组件接收数据: {this.state.lastName}</h1>
// 将该函数作为属性的值,传递给子组件
<Childs msg={this.handlers} />
</div>
)
}
}
// 子组件
class Childs extends React.Component {
state = {
lastName:'密码'
}
handlerClick = () => {
console.log(this.props)
// 子组件调用父组件中传递过来的回调函数
// 将子组件的数据作为参数传递给回调函数
this.props.msg(this.state.lastName)
}
render() {
return (
<div>
<button onClick={this.handlerClick}>点击传数据</button>
</div>
)
}
}
3.兄弟组件
- 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
- 公共父组件职责:1.提供共享状态 2.提供操作共享状态的方法
// 兄弟组件
class Parentss extends React.Component {
state = {
count:0
}
handlerClick = () => {
this.setState({count:this.state.count + 1})
}
render() {
return (
<div>
<Child1 count={this.state.count} />
<Child2 count2={this.handlerClick} />
</div>
)
}
}
const Child1 = (props) => {
return (
<div>
{props.count}
</div>
)
}
const Child2 = (props) => {
return (
<div>
<button onClick={() => props.count2()}>+1</button>
</div>
)
}
4.跨组件接收数据 Context
1.调用 React.createContext() 创建 Provider(提供数据) 和 Consumer(消费数据) 两个组件
const {Provider,Consumer} = React.createContext()
// 兄弟组件
class Parentss extends React.Component {
state = {
count:0
}
handlerClick = () => {
this.setState({count:this.state.count + 1})
}
render() {
return (
// 2.使用 Provider 组件作为父节点
// 3.设置 value 属性,表示要传递的数据
<Provider value={this.state.count}>
<div>
<Child1 count={this.state.count} />
<Child2 count={this.handlerClick} />
</div>
</Provider>
)
}
}
const Child1 = (props) => {
return (
<div>
{props.count}
</div>
)
}
const Child2 = (props) => {
return (
<div>
<button onClick={() => props.count()}>+1</button>
<Child3 />
</div>
)
}
const Child3 = () => {
return (
<div>
<div>11111111</div>
// 4.调用 Consumer 组件接收数据 data 就是value的属性值
<Consumer>
{data => <span>接收到的数据: {data}</span>}
</Consumer>
</div>
)
}