开发环境搭建 create-react-app 是一个快速创建 React 开发环境的工具,底层由 Webpack 构件,封装了配置细节
执行命令:
1 npx create-react-app react-test01
npx:Node.js 工具命令,查找并执行后续的包命令
create-react-app:核心包,用于创建 React 项目
react-test01:React 项目的名称(自定义)
创建项目的更多方法:https://zh-hans.react.dev/learn/start-a-new-react-project
使用命令运行项目:
成功进入项目页面
项目目录:
App.js:项目根组件
index.js:项目入口
JSX JSX 是 JavaScript 和 XML (HTML)的缩写,表示在 JS 代码中编写 HTML 模块结构,它是 React 中编写 UI 模块的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 const message = 'this is message' function App ( ) { return ( <div className ="App" > Hello React! <br /> {message} </div > ); } export default App ;
优势:
HTML 的声明式模块写法
JS 的可编程能力
JSX 并不是标准的 JS 语法,它是 JS 的语法扩展,浏览器本身不能识别 ,需要通过解析工具做解析 之后才能在浏览器中运行
JSX-表达式
使用引号传递字符串
使用JS变量
函数调用和方法调用
使用JavaScript对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const num = 666 const getNum = ( ) => { return num } function App ( ) { return ( <div className ="App" > Hello React! {/* 引号传递字符串 */} {'this is String'} {/* 使用JS变量 */} {num} {/* 函数调用和方法调用 */} {getNum()} {new Date().getDate()} {/* 使用JS对象 */} <div style ={{color: 'red '}}> Hello</div > </div > ); }
注意:if语句、switch语句、变量声明不属于表达式,不能出现在{}
中
JSX-实现列表渲染 在 JSX 中可以使用原生 JS 中的 map 方法遍历渲染列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const list = [ {id : 1001 , name : 'Vue' }, {id : 1002 , name : 'React' }, {id : 1003 , name : 'Angular' } ] function App ( ) { return ( <div className ="App" > <ul > {list.map(item=><li key ={item.id} > {item.id}{item.name}</li > )} </ul > </div > ); }
JSX-实现条件渲染 在 React 中,可以通过逻辑与运算符 &&
、三元表达式 ? :
实现基础的条件渲染
1 2 3 4 5 6 7 8 function App ( ) { return ( <div className ="App" > {true && <div style ={{color: 'red '}}> Hello</div > } {false ? new Date().getMonth() : new Date().getDate()} </div > ); }
JSX-实现复杂条件渲染 通过 自定义函数 的方式实现复杂条件渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const type = 1 function getArticleJSX ( ){ if (type === 0 ){ return <div > 无图模式模版</div > }else if (type === 1 ){ return <div > 单图模式模版</div > }else (type === 2 ){ return <div > 三图模式模版</div > } } function App ( ){ return ( <> { getArticleJSX() } </> ) }
React 事件绑定 基本实现 通过语法 on + 事件名称 = { 事件处理程序 }
1 2 3 4 5 6 7 8 9 function App ( ) { const clickHandle = ( ) => { console .log ('点击' ) } return ( <button onClick ={clickHandle} > 点击</button > ); } export default App ;
使用事件参数 在事件回调函数中设置形参即可
1 2 3 4 5 6 7 8 9 10 function App ( ) { const clickHandle = (e ) => { console .log ('点击了' , name) } return ( <button onClick ={clickHandle} > 点击</button > ); } export default App ;
传递自定义参数 事件绑定的位置改造成箭头函数的写法,在执行实际处理业务函数的时候传递实参
1 2 3 4 5 6 7 8 9 10 function App ( ) { const clickHandle = (name ) => { console .log ('点击了' , name) } return ( <button onClick ={() => clickHandle('按钮')}>点击</button > ); } export default App ;
注意:不能直接写函数调用,这里事件绑定需要一个函数引用
同时传递事件对象和自定义参数 在事件绑定的位置传递事件实参 e 和自定义参数,需要声明形参
1 2 3 4 5 6 7 8 9 10 function App ( ) { const clickHandle = (name, e ) => { console .log ('点击了' , name, e) } return ( <button onClick ={(e) => clickHandle('按钮', e)}>点击</button > ); } export default App ;
React 组件使用 在 React 中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI,渲染组件只需要把组件当成标签书写即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Button ( ){ return <button > click me</button > } function App ( ){ return ( <div > {/* 自闭和 */} <Button /> {/* 成对标签 */} <Button > </Button > </div > ) }
组件状态管理-useState useState 是一个 React Hook (函数),它允许我们向组件添加一个状态变量,从而实现响应式变量,控制组件渲染结构(数据驱动视图)
useState 是一个函数,返回值是一个数组
数组中的第一个参数是状态变量,第二个参数是 set 函数,用来修改状态变量
useState 的参数将作为 count 的初始值
1 2 3 4 5 6 7 8 9 10 11 12 13 import { useState } from "react" ; function App ( ) { const [count, setCount] = useState (0 ) const clickHandler = ( ) => { setCount (count + 1 ) } return ( <button onClick ={clickHandler} > {count}</button > ); } export default App ;
状态修改规则 在 React 中,状态是只读的 ,只能替换它不能修改它,直接修改不会引发视图更新
1 2 3 4 setCount (++count)setCount (count + 1 )
修改对象状态 对于对象类型的状态变量,始终传给 set 方法一个全新的对象 来进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { useState } from "react" ; function App ( ) { const [count, setCount] = useState ({ num : 0 , name : 'Alien' }) const clickHandler = ( ) => { setCount ({ ...count, num : count.num + 1 , name : 'React' }) } return ( <div > {count.name} <button onClick ={clickHandler} > {count.num}</button > </div > ); } export default App ;
组件样式处理
行内样式
1 <div style ={{ color: 'red '}}> this is div</div >
对象样式
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 const nameStyle = { color : 'blue' , fontSize : '50px' } function App ( ) { const [count, setCount] = useState ({ num : 0 , name : 'Alien' }) const clickHandler = ( ) => { setCount ({ ...count, num : count.num + 1 , name : 'React' }) } return ( <div > <div style ={nameStyle} > {count.name}</div > <button onClick ={clickHandler} > {count.num}</button > </div > ); } export default App ;
class 类名控制(导入样式表)
1 2 3 4 5 6 7 8 9 import './index.css' function App ( ){ return ( <div > <span className ="foo" > this is span</span > </div > ) }
React 表单控制 受控绑定 使用 React 组件的状态(useState)控制表单的状态
1 2 3 4 5 6 7 8 9 10 function App ( ){ const [value, setValue] = useState ('' ) return ( <input type ="text" value ={value} onChange ={e => setValue(e.target.value)} /> ) }
非受控绑定 通过获取 DOM 的方式获取表单的输入数据
在 React 组件中获取/操作 DOM,需要使用 useRef React Hook钩子函数,分为两步:
使用 useRef 创建 ref 对象,并与 JSX 绑定
在 DOM 可用时,通过 inputRef.current
拿到 DOM 对象
1 2 3 4 5 6 7 8 9 10 11 import { useRef } from "react" ; function App ( ) { const inputRef = useRef (null ) const onChange = ( ) => { console .log (inputRef.current .value ) } return ( <input type ="text" ref ={inputRef} onChange ={onChange} > </input > ); }
React 组件通信 父子通信-父传子
父组件传递数据:在子组件标签上绑定属性
子组件接收数据:子组件通过 props 参数接收数据
1 2 3 4 5 6 7 8 9 10 11 12 13 function Son (props ){ return <div > {props.text}</div > } function App ( ) { const name = 'this is name' return ( <div > <Son text ={name} > </Son > </div > ); }
props 可以传递任意的合法数据 ,比如数字、字符串、布尔值、数组、对象、函数、JSX
props是只读对象 ,子组件只能读取 props 中的数据,不能直接进行修改,父组件的数据只能由父组件修改
当我们的内容嵌套在组件的标签内部时,组件会自动在名为 children 的 props 属性中接收该内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function Son (props ){ return <div > {props.text}{props.children}</div > } function App ( ) { const name = 'this is name,' return ( <div > <Son text ={name} > <span > Hello React</span > </Son > </div > ); }
父子通信-子传父 在子组件中调用父组件中的函数并传递参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function Son (props ){ const sonMsg = 'this is son\'s message' return ( <div > {props.text}{props.children} <button onClick ={() => props.onGetMsg(sonMsg)}>OK</button > </div > ) } function App ( ) { const name = 'this is name,' const getMsg = (msg ) => console .log (msg) return ( <div > <Son text ={name} onGetMsg ={getMsg} > <span > Hello React</span > </Son > </div > ); }
兄弟组建通信 借助状态提升机制,通过共同的父组件进行兄弟之间的数据传递
A 组件先通过子传父的方式将数据传递给父组件 App
App 拿到数据之后通过父传子的方式传递给 B 组件
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 import { useState } from "react" function A ({ onGetAName }) { const name = 'this is A name' return ( <div > this is A compnent, <button onClick ={() => onGetAName(name)}>send</button > </div > ) } function B ({ name }) { return ( <div > this is B compnent, {name} </div > ) } function App () { const [name, setName] = useState ('' ) const getAName = (name ) => { setName (name) } return ( <div > this is App <A onGetAName ={getAName} /> <B name ={name} /> </div > ) }
跨层组件通信
使用createContext方法创建一个上下文对象MsgContext
在顶部组件中通过MsgContext.Provider组件提供数据
在底部组件中通过useContent钩子函数获取消费数据
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 import { createContext, useContext } from "react" const MsgContext = createContext () function A () { return ( <div > this is A component <B /> </div > ) } function B () { const msg = useContext (MsgContext ) return ( <div > this is B component,{msg} </div > ) } function App () { const msg = 'this is app msg' return ( <div > <MsgContext.Provider value ={msg} > this is App <A /> </MsgContext.Provider > </div > ) }
React 副作用管理-useEffect useEffect 是一个 React Hook 函数,用于在 React 组件中创建不是由事件引起而是由渲染本身引起的操作(副作用),比如发送 AJAX 请求、更改 DOM 等等
上面的组件中没有发生任何的用户事件,组件渲染完毕之后就需要和服务器要数据,整个过程属于”只由渲染引起的操作“
使用方法 在组件渲染完毕之后,立刻从服务端获取频道列表数据并显示到页面中
1 useEffect (() => { }, [])
参数1 是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作
参数2 是一个数组(可选参),在数组里放置依赖项 ,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次
依赖项
useEffect副作用函数的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现
依赖项
副作用函数的执行时机
没有依赖项
组件初始渲染 + 组件更新时执行
空数组依赖
只在初始渲染时执行一次
添加特定依赖项
组件初始渲染 + 依赖项变化时执行
消除副作用
在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用操作,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import { useEffect, useState } from "react" function Son () { useEffect (() => { const timer = setInterval (() => { console .log ('定时器执行中...' ) }, 1000 ) return () => { clearInterval (timer) } }, []) return <div > this is son</div > } function App () { const [show, setShow] = useState (true ) return ( <div > {show && <Son /> } <button onClick ={() => setShow(false)}>卸载Son组件</button > </div > ) }
消除副作用的函数最常见的执行时机是在组件卸载时自动执行
自定义Hook函数 自定义 Hook 是以 use 开头的函数,通过自定义 Hook 函数可以用来实现逻辑的封装和复用
声明一个以use打头的函数
在函数体内封装可复用的逻辑(只要是可复用的逻辑)
把组件中用到的状态或者回调return出去(以对象或者数组)
在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { useState } from "react" function useToggle () { const [value, setValue] = useState (true ) const toggle = ( ) => setValue (!value) return { value, toggle } } function App () { const { value, toggle } = useToggle () return ( <div > {value && <div > this is div</div > } <button onClick ={toggle} > toggle</button > </div > ) }
React Hooks 使用规则
只能在组件中或者其他自定义 Hook 函数中调用
1 2 3 4 const [value, setValue] = useState ('' ) function App ( ) { return () }
只能在组件的顶层调用,不能嵌套在if、for、其它的函数中
1 2 3 4 5 6 function App ( ) { if (Math .random () > 0.5 ) { const [value, setValue] = useState ('' ) } return () }
配置别名路径 通过配置可以实现将@/
解析为src/
,可以更加方便地填写路径
路径解析配置(webpack),把 @/
解析为 src/
路径联想配置(VsCode),VsCode 在输入@/
时,自动联想出来对应的 src/ 下的子级目录
路径解析配置 配置步骤 :
安装craco
项目根目录下创建配置文件 craco.config.js
配置文件中添加路径解析配置
包文件中配置启动和打包命令
联想路径配置 配置步骤:
根目录下新增配置文件jsconfig.json
添加路径提示配置
1 2 3 4 5 6 7 8 9 10 { "compilerOptions" : { "baseUrl" : "./" , "paths" : { "@/*" : [ "src/*" ] } } }