命令
npx create-react-app my-app
npx create-react-app my-app --template typescript
npm start
jsx
React认为视图的本质就是渲染逻辑与UI视图表现的内在统一,React把HTML与渲染逻辑进行了耦合,形成了JSX。
JSX的特点
- HTML代码可以与jsx兼容
- 可以在jsx中镶如表达式
- 使用jsx指定子元素
- 小驼峰命名。class变成了className、tabindex变成tabIndex
- jsx自定义属性,以 data- 开头
JSX 编译成对象
- jsx会被编译成
React.createElement()
对象
const element = (
<h1 className="greeting">hello</h1>
);
const element = React.createElement(
'h1',
{className='greeting' },
'hello'
);
// 这两种写法一样
// jsx 会被编译成React.createElement()对象
const element = { // 最后输出的对象
type: 'h1',
props: {
className:'greeting',
children:'hello'
}
}
css in js
新建custom.d.ts
这种文件可以被ts直接识别。不被编译不备打包
// 声明 CSS 文件。讲过声明后才可以被TS识别
declare module "*.css" {
const css: { [key: string]: string }
export default css
}
import style from './index.css'
<div className={style.app}></div>
npm install typescript-plugin-css-modules --save
加载媒体资源
新建assets文件夹。存储images、fonts、icons
class 组件
react组件必须继承React.Component
,这个组件接受一个泛型(Props,State,自定义数据)
class ShoppingCart extends React.Component<Props, State>{
constructor(props: Props) { // 传递来的Props
super(props); // 必须调用父类
this.state = { // 初始化state
isOpen: false,
}
}
render() {
return (
// DOM 元素
)
}
}
行内样式
行内样式接受一个采用小驼峰命名属性的js对象,可以预防xss攻击
const divStyle = {
color: 'blue'
}
// 在组件内使用时
return ( <div style={divStyle}></div> )
State和Props的区别
- props是组件对外的接口,而state是组件对内部的接口
- props用于组件间数据传递,而state用于组件内部的数据传递
用setState()修改State
this.setState({isOpen:false})
构建函数constructor是唯一可以初始化state的地方
constructor(props) {
super(props)
this.state = {
count: 0
}
}
- 调用setState后,state不会立即改变,是异步操作
- 不要依赖当前的state,计算下一个state
- state处理一般发生在声明周期变化的时候。(生命周期不变,state就是开始那个值)
<button onClick = {
this.setState((preState, preProps) => {
return {count: this.preState.count++}
}, ()=>{})
}>
</button>
Props
本质上,props就是传入函数的参数,是从外部传入组件内部的数据。就是父组件传递到子组件的数据。
props是只读属性
事件处理
handleClick = (e) => {
e.tatget // 描述的是时间发生的元素
e.currentTarger // 描述的是时间处理绑定的元素
}
react中的icon
npm install react-icons
<FcAddressBook />
组件方式使用
React生命周期
-
Mounting:创建虚拟DOM,渲染UI
-
Updating:更新虚拟DOM,重新渲染UI
-
Unmounting:删除虚拟DOM,移除UI
shouldComponentUpdate(nextProps, nextState) {
return (nextState.some! = this.state.some);
}
componentDidUpdate() {}
componentWillUnmount() {}
hooks(钩子)
一类特殊的函数,为你的函数型式组件注入特殊功能
Hooks的目的就是为了给函数式组件加上状态
- 消息处理的一种方法,用来监视指定程序
- 函数组件中需要处理副作用,可以用钩子把外部代码“沟进来”
- 常用钩子:useState、useEffect、useContext、useReducer
Hooks代表了React结构的一次重大变革。我们不再需要类组件了,不会再有this、binding、甚至可能取代redux,简化了代码、减少了模板、降低了学习难度
常用钩子
副作用
纯函数(pure function):给一个函数同样的参数,那么这个函数永远返回同样的。React组件接受相同的参数(props),渲染的UI应该永远一样。
副作用与纯函数相反:指一个函数处理了与返回值无关的事情。
useState()
import React, { useState } from "react";
const App:React.FC = (props) => {
const [count, setCount] = useState<number>(0)
return (
{count}
<button onClick={ () => {setCount(count+1)} }></button>
)
}
useEffect()
第二个参数不可为空,为空会死循环
import React, { useState, useEffect } from 'react'
const App: React.FC = (props) => {
const [robotGallery, setRobotGallery] = useState<any>([])
useEffect(() => {}) // 一直循环。
useEffect(() => {}, []) // 空数组表示模拟componentDidMount() {}
useEffect(() => {}, [count]) // 当count改变时触发函数
}
useEffect使用async
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("url")
const data = await response.json()
} catch (e) {
error = e.message
}
}
fetchData()
}, [])
**三元表达式 **
{ !loading ? (
// 显示代码
) : (
<h2>loading...加载中</h2>
)
}
二元表达式
{/* 错误处理 error不为空,为假就显示div*/}
{(!error || error !== '') && <div>{error}</div>}
全局数据传递 - AppState.tsx
- Context
- useContext()
在父组件index.tsx
const defaultContextValue = {
username: "rain"
}
export const appContext = React.createContext(defaultContextValue)
ReactDOM.render(
<React.StrictMode>
<appContext.Provider value={defaultContextValue}>
<App /> App是父组件
</appContext.Provider>
</React.StrictMode>,
document.getElementById('root')
);
子组件Robot.tsx(函数组件)
import React, { useContext } from 'react';
const value = useContext(appContext) // 使用useContext() 取值
<p>作者:{value.username}</p>
子组件Robot.tsx(类组件)
render() {
return (
<appContext.Consumer>
{(value) => {
return <div>{value.usename}</div>
}}
</appContext.Consumer>
)
}
自定义高阶组件HOC
const hoc = higherOrde(wrappedComponent)
高阶组件(HOC)就是返回了组件的函数,通过组件嵌套的方法给子组件添加更多的功能。
- 抽取重复代码,实现组件复用
- 条件渲染,控制组件的渲染逻辑
- 捕获/劫持被处理组件的生命周期
import React, { useContext } from 'react'
import { appSetStateContext } from '../AppState'
/**
* AddToCart.tsx
* 高阶组件HOC以 with开头 返回一个组件
* 改造了 Robot.tsx RobotDiscount.tsx
*/
import { RobotProps } from './Robot'
export const withAddToCart = (ChildComponent: React.ComponentType<RobotProps>) => {
// return class extends React.Component {}
// return ()=>{}
return (props) => {
const setState = useContext(appSetStateContext)
const addToCart = (id, name) => {
if (setState) {
setState((state) => {
console.log(state)
return {
...state,
shoppingCart: {
items: [...state.shoppingCart.items, { id, name }],
},
}
})
}
}
return <ChildComponent {...props} addToCart={addToCart} />
}
}
自定义Hook
use 开头。是函数。并非React特性。内部可调用替他Hook
export const useAddToCart = () => {
const setState = useContext(appSetStateContext)
const addToCart = (id, name) => {
if (setState) {
setState((state) => {
console.log(state)
return {
...state,
shoppingCart: {
items: [...state.shoppingCart.items, { id, name }],
},
}
})
}
}
return addToCart
}