组件的创建
类组件
类组件,顾名思义,也就是通过使用ES6类的编写形式去编写组件,该类必须继承React.Component
如果想要访问父组件传递过来的参数,可通过this.props
的方式去访问.在组件中必须实现render方法,在return中返回React对象,如下:
import React, { Fragment } from "react";
class App extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<Fragment>
<h1>hello world</h1>
</Fragment>
)
}
}
export default App
函数式组件
函数组件,顾名思义,就是通过函数编写的形式去实现一个React组件,是React中定义组件最简单的方式
function App(props) {
return (
<h1>hello world</h1>
)
}
//16.8之前--函数式组件叫无状态组件
//16.8之后--react hooks
export default App
函数第一个参数为props用于接收父组件传递过来的参数
区别
针对两种React组件,其区别主要分成以下几大方向:
- 编写形式
- 状态管理
- 生命周期
- 调用方式
- 获取渲染的值
编写形式
两者最明显的区别在于编写形式的不同,同一种功能的实现可以分别对应类组件和函数组件的编写形式
类组件:
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<Fragment>
<h1>hello world</h1>
</Fragment>
)
}
}
函数式组件:
function App(props) {
return (
<h1>hello world</h1>
)
}
状态管理
在hooks出来之前,函数组件就是无状态组件,不能保管组件的状态,不像类组件中调用setState
如果想要管理state状态,可以使用useState
,如下
const FunctionalComponent = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);
};
在使用hooks情况下,一般如果函数组件调用state,则需要创建一个类组件或者state提升到你的父组件中,然后通过props对象传递到子组件
生命周期
在函数组件中,并不存在生命周期,这是因为这些生命周期钩子都来自于继承的React.Component
所以,如果用到生命周期,就只能使用类组件
但是函数组件使用useEffect
也能够完成替代生命周期的作用,这里给出一个简单的例子:
const FunctionalComponent = () => {
useEffect(() => {
console.log("Hello");
}, []);
return <h1>Hello, World</h1>;
};
上述简单的例子对应类组件中的componentDidMount
生命周期
如果在useEffect
回调函数中return一个函数,则return函数会在组件卸载的时候执行,正如componentWillUnmount
const FunctionalComponent = () => {
React.useEffect(() => {
return () => {
console.log("Bye");
};
}, []);
return <h1>Bye, World</h1>;
};
调用方式
如果是一个函数组件,调用则是执行函数即可:
function SayHi() {
return <p>Hello, React</p>
}
// React内部
const result = SayHi(props) // » <p>Hello, React</p>
果是一个类组件,则需要将组件进行实例化,然后调用实例对象的render方法:
class SayHi extends React.Component {
render() {
return <p>Hello, React</p>
}
}
// React内部
const instance = new SayHi(props) // » SayHi {}
const result = instance.render() // » <p>Hello, React</p>
获取渲染的值
首先给出一个示例
函数组件对应如下:
function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
}
const handleClick = () => {
setTimeout(showMessage, 3000);
}
return (
<button onClick={handleClick}>Follow</button>
)
}
类组件对应如下:
class ProfilePage extends React.Component {
showMessage() {
alert('Followed ' + this.props.user);
}
handleClick() {
setTimeout(this.showMessage.bind(this), 3000);
}
render() {
return <button onClick={this.handleClick.bind(this)}>Follow</button>
}
}
因此,如果我们的组件在请求运行时更新。this.props 将会改变。showMessage方法从“最新”的 props 中读取 user
而函数组件,本身就不存在this,props并不发生改变,因此同样是点击,alert的内容仍旧是之前的内容
组件样式
React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体
- 内联样式
- 对象样式
- 选择器样式
- 模块化
内联样式
内联样式必须作为对象而不是字符串编写
import React, { Component, Fragment } from 'react'
export default class Style extends Component {
render() {
return (
<div style={{ backgroundColor: "yellow" }}>hello world</div>
)
}
}
在上面的style属性中,第一组花括号将告诉您的JSX解析器,括号之间的内容是JavaScript(而不是字符串)。 第二组花括号将初始化一个JavaScript对象。
具有多个单词的样式属性名称是使用camelCase编写的,而不是使用传统的连字符样式。 例如,通常的background-color属性必须在JSX中写为backgroundColor
对象样式
因为style属性是一个对象,所以您还可以通过将其编写为常量来分隔样式。 这样,您可以根据需要在其他元素上重用它:
import React, { Component } from 'react'
export default class Style extends Component {
render() {
const styleObj = {
backgroundColor: "red"
}
return (
<div style={styleObj}>hello world</div>
)
}
}
如果需要将段落样式进一步扩展,可以使用对象传播运算符。 这将使您可以将内联样式添加到已经声明的样式对象中:
import React, { Component } from 'react'
export default class Style extends Component {
render() {
const styleObj = {
backgroundColor: "red"
}
return (
<div style={{...styleObj, color: white}}>hello world</div>
)
}
}
选择器样式
可以使用JavaScript import
语法将.css文件导入到JavaScript文件中。 然后,您可以在要设置样式的JSX元素中使用CSS类名称,如下所示:
style.css文件
.blue{
background-color: blue;
color:white
}
jsx文件
import React, { Component } from 'react'
import "./style.css"
export default class Style extends Component {
render() {
return (
<div className="blue">hello world</div>
)
}
}
模块化
每个React组件都有其自己CSS文件,您需要将所需CSS文件导入到您的组件中。
为了让React知道您正在使用CSS模块,请使用[name].module.css
约定来命名CSS文件
App.module.css文件
.BlueParagraph {
color: blue;
text-align: left;
}
.GreenParagraph {
color: green;
text-align: right;
}
jsx文件
import React from "react";
import styles from "./App.module.css";
export default function App() {
return (
<>
<p className={styles.BlueParagraph}>
The weather is sunny with a small chance of rain today.
</p>
<p className={styles.GreenParagraph}>
When you go to work, don't forget to bring your umbrella with you!
</p>
</>
);
}
事件绑定
在 React 底层,主要对合成事件做了两件事:事件委派和自动绑定。
事件委派
在使用 React 事件前,一定要熟悉它的事件代理机制。==它并不会把事件处理函数直接绑定到真实的节点上,而是把所有事件绑定到结构的最外层,使用一个统一的事件监听器,在这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。==当组件挂载或卸载时,只是在这个统一的事件监听器上插入或删除一些对象;当事件发生时,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用。这样做简化了事件处理和回收机制,效率也有很大的提升。
自动绑定
在 React 组件中,每个方法的上下文都会指向该组件的实例,即自动绑定 this 为当前组件。而且 React 还会对这种引用进行缓存,以达到 CPU 和内存的最优化。在使用 ES6 classes 或者纯函数时,这种自动绑定就不复存在了,需要手动实现 this 的绑定。
有几种绑定的方法如下:
方案一:在事件中通过bind绑定this(显示绑定)用的较少
<button onClick={this.hanldEvent.bind(this)}></button>
方案二:同一绑定this
this.hanldEvent = this.hanldEvent.bind(this)
hanldEvent(){
console.log(this)
}
<button onClick={this.hanldEvent}></button>
方案三:通过箭头函数绑定this
<button onClick={this.hanldEvent}></button>
hanldEvent=()=>{
console.log(this);
}
方案四:最常用的方法(推荐)直接传入箭头函数,在箭头函数中调用需要调用的箭头函数。标准写法
<button onClick={e=>{
this.hanldlist('why',) //可以传任何的参数
}}>点我</button>
hanldlist(name,evnet){
console.log(this.state.message,name,evnet);
}