Closed xccjk closed 1 year ago
16.8版本推出Hooks后,对以前的Class组件完全没影响。原来的Class组件完全可以继续使用,这两种开发方式是并存的,已有代码不需要任何改动,新的逻辑可以看具体情况来采用Hooks方法来实现
相比Vue的版本升级,React的每次版本升级,都是向后兼容的,每次版本升级也非常的丝滑
所有的UI都是由状态来驱动的。状态发生变化时,UI会自动变化,这就是数据绑定
逻辑复用能力强
react class render props实现获取鼠标在页面的位置的逻辑复用
mouse-position.js
import React, { Component } from 'react'
class MousePosition extends Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
}
}
handleMouseMove = (e) => {
const { clientX, clientY } = e
this.setState({
x: clientX,
y: clientY
})
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove)
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
const { children } = this.props
const { x, y } = this.state
return(
<div>
{
children({x, y})
}
</div>
)
}
}
app.js
import React from "react";
import MousePosition from "./mouse-position";
export default function App() {
return (
<div className="App">
<MousePosition>
{({ x, y }) => {
return (
<div>
<p>
x:{x}, y: {y}
</p>
</div>
);
}}
</MousePosition>
</div>
);
}
react class hoc实现获取鼠标在页面的位置的逻辑复用
mouse-position.js
import React from "react";
const MousePosition = (Component) => {
class MousePositionComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 0,
y: 0
};
}
handleMouseMove = (e) => {
const { clientX, clientY } = e;
this.setState({
x: clientX,
y: clientY
});
};
componentDidMount() {
document.addEventListener("mousemove", this.handleMouseMove);
}
componentWillUnmount() {
document.removeEventListener("mousemove", this.handleMouseMove);
}
render() {
const { x, y } = this.state;
return <Component x={x} y={y} />;
}
}
return MousePositionComponent;
};
export default MousePosition;
app.js
import React from "react";
import MousePosition from "./mouse-position";
function App({ x, y }) {
return (
<div>
<p>
x:{x}, y: {y}
</p>
</div>
);
}
export default MousePosition(App);
use-position.js
import { useState, useEffect } from "react";
const usePosition = () => {
const [position, setPosition] = useState({
x: 0,
y: 0
});
const handleMouseMove = (e) => {
const { clientX, clientY } = e;
setPosition({ x: clientX, y: clientY });
};
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
};
}, []);
return position;
};
export default usePosition;
app.js
import React from "react";
import usePosition from "./use-position";
export default function App() {
const position = usePosition();
return (
<div>
<p>
x:{position.x},y:{position.y}
</p>
</div>
);
}
代码更加精简
class实现计时器组件:
import React from 'react'
class Counter extends Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
handleClick = () => {
let { count } = this.state
this.setState({
count: count+1
})
}
render() {
const { count } = this.state
return (
<div>
<p>{ count }</p>
<button onClick={this.handleClick}>点击</button>
</div>
)
}
}
export defaule Counter
hooks实现计时器组件:
import React, { useState } from 'react'
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{ count }</p>
<button onClick={() => setCount(count + 1)}>点击</button>
</div>
)
}
export default Counter
业务代码更加聚合
class组件中监听页面缩放:
import React from 'react'
class WindowSize extends Component {
constructor(props) {
super(props)
this.state = {
size: null
}
}
componentDidMount() {
window.addEventListener("resize", this.handleResize)
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleResize)
}
handleResize = () => {
...
}
render() {
...
}
}
export default WindowSize
hooks组件监听页面缩放:
import React, { useState, useEffect } from 'react'
const WindowSize = () => {
const [size, setSize] = useState(null)
useEffect(() => {
const handleResize = () => {
...
}
window.addEventListener("resize", handleResize)
return () => {
window.removeEventListener("resize", handleResize)
}
}, [])
return (
...
)
}
export default WindowSize
useState,让函数组件拥有了维持状态的功能。维持状态是指在函数的多次渲染之间,这个state是可以在函数中间共享的
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{ count }</p>
<button onClick={() => setCount(count + 1)}>点击</button>
</div>
)
}
export default Counter
useState(initialState)的参数initialState是state的初始值,可以是任意类型,如字符串、数值、布尔值、对象、数组
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const [visible, setVisible] = useState(false);
const [store, setStore] = useState({});
const [list, setList] = useState([]);
const [name, setName] = useState('xcc');
return ...
}
export default Counter
useState()返回值是一个包含两个元素的数组,第一个值为state的值,为只读的,第二个是用来设置state值的
类组件只有一个state,通过通过对象中的不同属性来表示不同的状态,通过setState来进行更新。函数组件可以创建多个state,用来描述不同状态的值,更加语义化
类组件:
import React from 'react'
class Counter extends Component {
constructor(props) {
super(props)
this.state = {
count: 0,
visible: false
}
}
componentDidMount() {
setState({ count: 1 })
}
render() {
...
}
}
export default Counter
函数组件:
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const [visible, setVisible] = useState(false);
return ...
}
export default Counter
不要在state中存储可以通过计算得到的值
常见情况:
useEffect,用来执行一段副作用,副作用是指一段和当前执行结果无关的代码。其中代码的执行是不会影响UI的渲染
import React, { useState, useEffect } from 'react'
const WindowSize = () => {
const [size, setSize] = useState(null)
useEffect(() => {
const handleResize = () => {
...
}
window.addEventListener("resize", handleResize)
return () => {
window.removeEventListener("resize", handleResize)
}
}, [])
return (
...
)
}
export default WindowSize
useEffect(callback, dependencies)
callback为要执行的函数,dependencies为可选的依赖项数组
几种常见的使用方式:
没有依赖项时,会在每次render后执行
useEffect(() => {})
依赖项为空数组时,会在首次render后执行
useEffect(() => {}, [])
依赖项不为空时,会在首次render后,每次依赖项数组发生改变时执行
useEffect(() => {}, [a,b,c])
组件在卸载时执行
useEffect(() => { return () => {} }, [])
useEffect想比类组件的生命周期,基本可以等价于ComponentDidMount、componentDidUpdate 和 componentWillUnmount这三个方法,但有不是完全相同
类组件
import React from 'react'
class WindowSize extends Component {
constructor(props) {
super(props)
this.state = {
size: null
}
}
componentDidMount() {
window.addEventListener("resize", this.handleResize)
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleResize)
}
handleResize = () => {
...
}
render() {
...
}
}
export default WindowSize
函数组件:
import React, { useState, useEffect } from 'react'
const WindowSize = () => {
const [size, setSize] = useState(null)
useEffect(() => {
const handleResize = () => {
...
}
// 等价于类组件中的componentDidMount
window.addEventListener("resize", handleResize)
// 等价于类组件中的componentWillUnmount
return () => {
window.removeEventListener("resize", handleResize)
}
}, [])
return (
...
)
}
export default WindowSize
依赖项一定要为回调函数中在使用的变量
import React, { useState, useEffect } from 'react'
const Books = ({ id }) => {
const [list, setList] = useState([])
useEffect(() => {
const getList = async () => {
const res = await getBookList({ id })
setList(res.data)
}
getList()
}, [id])
return ...
}
export defaule Books;
依赖项要为一个常量数组,而不是一个动态数据
useEffect(() => {}, [id])
React会使用浅比较来对比依赖项是否发生改变,因此不要使用对象、数组等作为依赖项
function Todos() {
// 这里在每次组件执行时创建了一个新数组
const todos = [{ text: 'Learn hooks.'}];
useEffect(() => {
console.log('Todos changed.');
}, [todos]);
}
01-如何创建React应用
传统开发UI的方式:
基于浏览器DOM的API,来控制DOM节点的创建、修改、删除。为了保证UI的一致性,需要非常小心处理各种数据导致的UI变化
React开发UI的方式:
当数据发生变化时,UI能够自动把变化反应出来。用声明式的方式来描述数据和UI之间的关系
React的基本概念
React的三个基本概念:组件、状态、jsx
组件
组件分为内置组件和自定义组件,自定义组件必须以大写开头。React组件是以树结构组织在一起的,一个React应用通常只有一个根组件
一个评论组件的组织方式:
state 和 props来进行状态管理
state是用来在组件内部保存状态的
一个计数器组件:
props是用来在父子组件自检传递状态
一个用户信息展示组件:
jsx本质
jsx并不是一种新的模板语言,而可以认为是一种语法糖。React也可以不使用jsx语法来实现
计数器组件的非jsx语法实现:
通过React.createElement API创建一个组件的实例,这个API会接收一组参数:
常见创建React应用的方式
一个React应用,应该包含路由管理、状态管理、JavaScript新语言特性的支持、CSS预处理框架等
使用create-react-app创建应用