React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。
官网。
JSX
React 中一般用 JSX 输出 UI。JSX 可以简单的理解为,包含 JavaScript 表达式的 HTML 。
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
渲染列表
item 上一定要加 key。不要用数组的下标做为 Key。用数组的下标做为 Key 会有性能问题。
<ul>
{list.map(item =>
(<li key={item.id>{item.name}</li>)
}
</ul>
条件渲染
{isShow && <div>...</div>}
<b>{isLoggedIn ? 'currently' : 'not'}</b>
一个组件返回多个元素
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
简写
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
事件
绑定事件
React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
<button onClick={activateLasers}>
Activate Lasers
</button>
回调中获取事件对象 & 传额外参数
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
停止冒泡到原生的事件
<div onClick={e => e.nativeEvent.stopImmediatePropagation()}>...</div>
类组件
组件 API
setState(changeState, cb)
大部分情况是异步的。
生命周期
render()
返回要渲染的元素。
constructor
主要用来设置 state 的初始值。
constructor(props) {
super(props);
// 不要在这里调用 this.setState()
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
componentDidMount()
DOM 加载好后会被调用。通常放下面的操作:
- 依赖于 DOM 节点的初始化操作。
- 接口调用。
componentDidUpdate(prevProps, prevState, snapshot)
组件更新后会被调用。通常放下面的操作:
- 监控 props 或 state 的变化。
- 对 DOM 进行额外的操作。
注意: componentDidUpdate() 中直接调用 setState() 必须被包裹在一个条件语句里,否则会导致死循环。componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
componentWillUnmount()
componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
函数组件
Hook API
useState
存数据。
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useContext
const ctx = React.createContext()
const { Provider, Consumer } = ctx
<Provider value={{name: 'joel'}}>
<Child />
</Provider>
function Child() {
const nameCtx = useContext(ctx)
return <div>{nameCtx.name}</div>
}
useEffect
执行副作用。
useEffect(() => {
fetchInitData()
window.addEventListener('mouseup', handleStopResizing);
return () => {
window.removeEventListener('mouseup', handleStopResizing);
};
}, [])
useEffect(() => {
fetchDetail(id)
}, [id])
useLayoutEffect
在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。
useCallback
给子组件传函数类型的属性,要用 useCallback。
const handleClick = useCallback(() => {}, [...])
return (
<Sub onClick={handleClick} />
)
组件间通信
父子
父给子传参
props。
子通知父
调用 props 的函数。
父主动让子做些事
方案1: 主动调用。用 refs。
方案2: 子监控父组件的属性。
兄弟
共用数据的改变
状态提升。
祖先和子
祖先给子传参
方案1: 一层层往下传。
方案2: Context API。
类组件:
const ctx = React.createContext()
const { Provider, Consumer } = ctx
<Provider value={{name: 'joel'}}>
<Consumer>
{ctx => ( // Provider 上 value 属性的值
<Component
{...props}
name={ctx.name}
/>
)}
</Consumer>
</Provider>
函数组件
const ctx = React.createContext()
const { Provider, Consumer } = ctx
<Provider value={{name: 'joel'}}>
<Child />
</Provider>
function Child() {
const nameCtx = useContext(ctx)
return <div>{nameCtx.name}</div>
}
祖先让子做些事
方案1: 主动调用。用 forwoardRef。
方案2: 子监控祖先组件的属性。
组件复用
单一职责
UI 和 逻辑的分离。对应的是展示组件 和 容器组件。
多组件共用数据的分离。将数据和对数据操作的放在一起。
高阶组件(HOC)
// 定义
function withName (Component) {
return (props) => <Component {...props} name="Joel"/>
}
// 使用。用装饰器看起来更舒服。
const WithNameComp = withName(Comp)
Render Props
// 定义
function Provider (props) {
return <div>{props.children({name: 'Joel', ...props})}</div>
}
// 使用
<Provider>
{(props) => {
return <Comp name={props.name}/>
}}
</Provider>
Use Hooks
// 定义
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
// 使用
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id)
}