前言
React的基本部分,包括Class与Hook的语法。
class类与对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Animal { //构造 constructor(name) { this.name = name; }
run() { return console.log(this.name + '跑') }
//静态方法 static eat(name) { return console.log(name + '吃') // 注意这里this.name是没有值,下面调用没有给 } }
// 类(Animal)通过实例化(new)变为对象(pig) const pig = new Animal('小猪'); pig.run()
// 静态方法直接通过类方法名来调用 Animal.eat('猫');
class Bird extends Animal { constructor(name, color = '黄色') { //super调用父类的代码 super(name); this.color = color; }
run() { super.run() // 可以不覆盖原函数的方法 // 输出鹦鹉跑 return console.log(this.name + this.color) // 输出鹦鹉黄色 } }
const polly = new Bird('鹦鹉'); polly.run();
|
项目命令
1 2 3 4 5 6 7 8
| // 安装项目 npx create-react-app demo // 或者 yarn create react-app demo // Ant Design安装 yarn add antd // 启动命令 yarn start
|
Class组件介绍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| // class组件,先引用Component import React, {Component} from 'react' class App extends Component { // 构造器 constructor(props) { super(props) this.state = { count: 0 } } // render() { return ( // Fragments概念(或者<React.Fragment></React.Fragment>) <> {/* 设置和读取state里面的值 */} <p>你点击了 {this.state.count} 次</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> 点我 </button> </> ) } } // 导出App export default App
|
生命周期

Class的this指向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class App extends Component { constructor(props) { super(props); // 第一种:为了在回调中使用this,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this) } handleClick() {alert(this)} // class fields写法 // handleClick=()=> {alert(this)} render() { return ( {/*这里可以直接找到handleClick*/} {/*第二种:直接onClick={()=>{this.handleClick}};上面不做变化,相当于事件放在这里*/} <button onClick={this.handleClick}>点这里</button> ) } }
|
父子传值props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // 子组件 class Welcome extends React.Component { render() { return ( <h1 onClick={() => this.props.handleClick('参数')}>{this.props.name}</h1> ); } } // 父组件 class App extends Component { render() { return ( <Welcome name="Aaron" handleClick={(value) => {console.log(value,'Aaron')}}/> ) } }
|
条件渲染、列表循环、表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import React, {Component} from 'react'
class App extends Component { constructor(props) { super(props) this.state = {show: true,data: [],name:''} } handleClick() { this.setState(state => {return {show: !state.show}}) } handleChange(value) { this.setState({name: value.target.value}) } handleSubmit(value) { alert('提交的名字: ' + this.state.name) value.preventDefault() // 防止刷新(原生方法) } render() { const {data, show, name} = this.state // 取值 return ( <> {/*条件渲染或者使用三目运算符*/} {/*{show ? <p>显示出来了</p> : ''}*/} {show && <p>显示出来了</p>} <button onClick={() => this.handleClick()}>点这里</button> {/*列表循环*/} data.map((item) =><li key={item.id.toString()}>{item.name}</li>) {/*表单,双向绑定*/} <form onSubmit={(value) => this.handleSubmit(value)}> <input type="text" value={name} onChange={(value) => this.handleChange(value)}/> <input type="submit" value="提交"/> </form> </> ) } } export default App
|
Hook组件介绍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import React, { useState, useEffect } from 'react';
function App() { // 声明一个叫 "count" 的 state 变量,并定义了设置count值的方法 "setCount" const [count, setCount] = useState(0); // 生命周期的作用 // 读取数据函数 const fetchData = ()=>{} useEffect(() => { // 里面调用 fetchData(); // 下面写上[]表示执行一次,写上具体的值就表示监听 },[]); return ( <div> <p>你点击了 {count} 次</p> <button onClick={() => setCount(count + 1)}>点我</button> </div> ); } export default App
|
Hook实现搜索、加载、错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| // 双向绑定 const [keyword, setKeyword] = useState(''); // 请求的地址后接上keyword <input type="text" value={keyword} // 用户输入的内容,设置给state中的keyword onChange={(value) => { setKeyword(value.target.value) console.log(value.target.value) }}/> // 加载 const [loading, setLoading] = useState(false); // 请求开始前,loading=true setLoading(true); // 请求完成后,loading=false setLoading(false); // return里面写上 {/*根据loading的值,判断是显示加载中,或是课程列表?*/} {loading ? (<div>加载中...</div>) : (<div>加载成功</div>)} // 错误处理 const [error, setError] = useState(false); // 请求开始前,error=false setError(false); axios(`xxx`).then(res => {}).catch(error => { //发生了错误,设置error=true setError(true); }).finally(() => {setLoading(false)})} // 判断接口读取错误 if (error) { return (<button onClick={fetchData}>立即重试</button>)}
|
Hook扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| // 使用useContext,组件之间直接传值 import {React,useContext} from 'react'; // 创建一个context对象,默认值为themes const ThemeContext = React.createContext(themes); function A() { return ( // 使用ThemeContext包裹子组件 <ThemeContext.Provider value={themes.dark}> <B/> </ThemeContext.Provider> ); } function B() {return (<div><C/></div>)} function C() { // 使用useContext,就能直接读取到A组件中传递过来的value了 const theme = useContext(ThemeContext); return ( <button style={{background: theme.background}}>A直接传C</button> ); }
// 重复渲染子组件的情况 // memo-当组件的props或者state变化时,会重新渲染页面,触发页面重新渲染。防止子组件重新渲染 // 使用 React.memo() import {memo} from 'react'; const Child = memo(() => {return (<div>子组件</div>)}) // 或者 let Child = function () {return (<div>子组件</div>)} Child = memo(Child)
// useCallback-当子组件有父组件中的方法(props),也会重新渲染 import {useCallback} from 'react'; // 子组件中的方法写上useCallback(后页可以监听) const handleClick = useCallback(() => { console.log("子组件的按钮被点击了...") }, []) // useMemo-当传递值为对象时,再次重复渲染 // useMemo 包裹一下值 const data = useMemo(() => ({ title: '这里是子组件' }), []) // 第二个参数作为依赖项可以当做成计算属性使用 const fullName = useMemo( () => lastName + firstName, [firstName, lastName], );
|
路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| // 安装 yarn add history@5 react-router-dom@6 // 使用路由src/index.js文件中 import {BrowserRouter} from "react-router-dom"; // 删除严格模式(防止antdesign有报错) <React.StrictMode></React.StrictMode> // 删除掉 // 使用路由 <BrowserRouter><App/></BrowserRouter>
// src/App.js中修改 import * as React from "react"; import { Routes, Route, Link } from "react-router-dom"; // 注意引用的组件取名首字母大写 function App() { return ( <Routes> <Route path="/" element={<Home/>}> <Route path="about/:id" element={<About/>}/> {/* 使用 path="*",所有未匹配的路由,都会到这里来这里*/} <Route path="*" element={<NoMatch/>}/> {/* 使用index,index路由和他的父路由路径是一样*/} <Route index element={<Home/>}/> </Route> </Routes> ) }
// 路由出口 import { Link, Outlet } from "react-router-dom"; <Outlet /> // 首页组件中写上 <Link to={`/about/${id}`}</Link>
// 获取 URL 参数 import { useParams } from "react-router-dom"; let params = useParams(); let id = params.id
// 链接激活高亮显示 import { NavLink } from "react-router-dom"; // Link修改为NavLink,使用isActive判断当前链接是否被激活 <NavLink style={({ isActive }) => { return { color: isActive ? "red" : "",display: "block"} } } to={`/about/${id}`}> </NavLink>
// 使用代码跳转 import {useNavigate} from "react-router-dom"; let navigate = useNavigate(); // 使用跳转 navigate("/")
// 其他属性 // useSearchParams搜索参数 import {useSearchParams} from "react-router-dom"; let [searchParams, setSearchParams] = useSearchParams(); // useLocation,可以返回path等信息,解决 import {useLocation} from "react-router-dom"; let location = useLocation();
// 懒加载(按需加载) const About = React.lazy(() => import("xxx")); <Route path="/about" element={ // 使用React.Suspense因为组件是懒加载,在渲染时被暂停了, // react无法得知渲染内容,为了避免报错使用Suspense来进行空档期的显示 <React.Suspense fallback={<>空档期显示的组件</>}> <About/> </React.Suspense>} />
|
useReducer 统一管理状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| // 引用 useReducer import {useEffect, useReducer} from 'react'; import axios from 'axios';
// 初始状态 // Data是初始值,如果用户不传,默认就是 [] let initialState = { loading: false, error: false, data: [], } // 定义reducer,统一管理状态 const reducer = (state, action) => { switch (action.type) { case 'init': return { ...state, loading: true, error: false }; case 'success': return { ...state, loading: false, error: false, data: action.payload }; case 'failure': return { ...state, loading: false, error: true }; default: throw new Error(); } };
// 自定义hook const useFetchData = (url, initData) => { // 如果有传过来的initData,设置到initialState里 initialState = { ...initialState, data: initData || [], } // 使用useReducer初始化数据 const [state, dispatch] = useReducer(reducer, initialState); // 接口请求 const fetchData = url => { dispatch({type: 'init'});
axios(url).then(res => { // 成功的状态 // 注意封装出去有四次请求,刷新开始为空; // 在页面上有data.data出现undefined;后还需data.data.xxx时会报错; // 解决:在这里写上res.data.data,或者在那边将initData设置为{data:{},xxx:[]}等; dispatch({type: 'success', payload: res.data.data}); }).catch(error => { // 失败的状态 dispatch({type: 'failure'}); }) } // 监听 url 参数,也就说当接口地址变化后,会重新请求接口 useEffect(() => { fetchData(url); }, [url]);
// ...state解出来,就是loading、error和data // 返回这些内容,在调用的页面中可以读取、调用,或再次进行设置 return {...state, fetchData}; }
export default useFetchData;
|
项目中的一些问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| // antd安装 yarn create react-app antd-demo
// class的生命周期不用解决this,其他需要 componentDidMount() { this.handleClick() } handleClick() { console.log(this) // 可以打印 }
// onClick事件调用方法是否跟() handleClick() {console.log(1)} // 进来就调用 // 声明时就直接执行了(因而加载页面自动执行) // 执行后的返回值赋给了onClick属性(返回值必然不会是个函数,因而再点击没有作用) <button onClick={this.handleClick()}>点这里</button> // 点击后调用 <button onClick={() => this.handleClick()}>点这里</button>
// 注意setState是异步操作的
// 刷新页面 window.location.reload()
// 视频标签 <video src=11111 controls />video.js
// 注意key(循环和表格) <Table rowKey="id"></Table> // 样式要写成{{}}, 里面对象形式,或者取名id,在APP.css里面写
|