React初学分享 事件绑定 组价通信 useState useEffect
React初学
- React介绍
- 快速搭建React项目
- JSX
- JSX的本质
- 优势:
- JSX中使用JS表达式
- JSX中的列表渲染
- JSX实现简单条件渲染
- JSX实现复杂条件渲染
- React中的事件绑定
- React基础事件绑定
- 传递自定义参数
- 同时传递事件对象和自定义参数
- React中的组件
- useState
- 修改状态的规则
- 状态不可变
- 修改对象状态
- 受控表单绑定
- React中获取DOM元素
- 组件通信
- 理解组件通信
- 父传子
- props说明
- 特殊的prop children
- 子传父
- 使用状态提升实现兄弟组件通信
- 使用Context机制跨层级组件通信
- useEffect
- useEffect依赖项参数说明
- useEffect --- 清除副作用
- 自定义Hook实现
- 封装自定义hook通用思路
- React Hooks使用规则
React介绍
- React是一个用于构建Web和原生交互界面的库
快速搭建React项目
- create-react-app是一个快速创建React开发环境的工具,底层由Webpack构建,封装了配置细节,开箱即用
- 执行命令:npx create-react-app name
JSX
- JSX是JavaScript和XML的缩写,表示在JS代码中编写HTML模版结构,它是React编写UI模版的方式
JSX的本质
- JSX并不是标准的JS语法,它是JS语法的扩展,浏览器本身不能识别,需要通过解析工具做解析之后才能在浏览器中运行
优势:
- HTML的声明式模版写法
- JS的可编程能力
JSX中使用JS表达式
- 在JSX中可以使用大括号语法{}识别JavaScript中的表达式,比如常见的变量、函数调用、方法调用等等
注意:if语句、Switch语句、变量声明属于语句,不是表达式,不能出现在{}中
JSX中的列表渲染
- 语法:在JSX中可以使用原生JS中的map方法遍历渲染列表
//项目的根组件
const list = [
{id:1001,name:"vue"},
{id:1002,name:"react"},
{id:1003,name:"angular"}
]
function App() {
return (
<div className="App">
this is app
{/* 渲染列表 */}
<ul>
{/* key的作用:React框架内部使用 提升更新性能 */}
{list.map((item)=><li key={item.id}>{item.name}</li>)}
</ul>
</div>
);
}
JSX实现简单条件渲染
- 语法:在React中,可以通过逻辑运算符&&或者三元表达式(?:)实现基础的条件渲染
const isLogin = false
function App() {
return (
<div className="App">
{/* 逻辑与 */}
{isLogin && <span>this is span </span>}
{/* 三元运算 */}
{isLogin ? <span>miraculous</span> : <span>loading...</span>}
</div>
);
}
JSX实现复杂条件渲染
- 自定义函数+if判断语句
//项目的根组件
const articleType = 3 //0||1||3
//根据不同的类型返回不同的JSX模版
const getArticleForm = ()=>{
if(articleType === 0){
return <div>我是无图模式</div>
}else if(articleType === 1){
return <div>我是单图模式</div>
}else{
return <div>我是三图模式</div>
}
}
function App() {
return (
<div className="App">
{/* 复杂的条件渲染 */}
{/* 调用函数来实现 */}
{getArticleForm()}
</div>
);
}
React中的事件绑定
React基础事件绑定
- 语法:
on + 事件名称 = {事件处理程序}
,整体上遵循驼峰命名法
function App() {
//点击按钮后处理函数
const handleClick = ()=>{
console.log("点上了按钮");
}
return (
<div className="App">
<button onClick={handleClick}>click me</button>
</div>
);
}
传递自定义参数
- 事件绑定的位置改造成箭头函数的写法,在执行相关回调函数传递实参
注意:不能直接写函数调用,这里事件绑定需要一个函数引用
function App() {
//点击按钮后处理函数
const handleClick = (name)=>{
console.log("点上了按钮",name);
}
return (
<div className="App">
<button onClick={()=>handleClick('miraculous')}>click me</button>
</div>
);
}
同时传递事件对象和自定义参数
- 在事件绑定的位置传递事件实参e和自定义参数,执行函数中声明形参,注意顺序对应
function App() {
//点击按钮后处理函数
const handleClick = (name,e)=>{
console.log("点上了按钮",name,e);
}
return (
<div className="App">
<button onClick={(e)=>handleClick('miraculous',e)}>click me</button>
</div>
);
}
React中的组件
- 定义:在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI,渲染组件只需要把组件当成标签渲染即可
//自定义组件
const Button = ()=>{
return <button>click me</button>
}
function App() {
return (
<div className="App">
{/* 自闭和 */}
<Button />
{/* 成对标签 */}
<Button></Button>
</div>
);
}
useState
- useState是一个React Hook(函数),它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果
- 本质:和普通js变量不同的是,状态变量一旦发生变化,组件的视图UI也会跟着变化(数据驱动视图)
const [count,setCount] = useState(0)
- useState是一个函数,返回值是一个数组
- 数组的第一个参数是状态变量,第二个参数是Set函数用来修改状态变量
- useState的参数将作为count的参数值
//使用useState完成一个计数器
import { useState } from "react";
//useState实现一个计数器
function App() {
const [count,setCount] = useState(0)
//点击事件回调
const handleClick = ()=>{
setCount(count+1)
}
return (
<div className="App">
<button onClick={handleClick}>{count}</button>
</div>
);
}
修改状态的规则
状态不可变
- 在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新
修改对象状态
- 规则:对于对象类型的状态变量,应该始终传给set方法一个全新的对象来进行修改
- 错误写法:直接修改
const [form,setForm] = useState({name:"yaoyao"})
//修改form中的name
form.name = "miraculous"
- 正确写法:setForm传入一个全新的对象
const [form,setForm] = useState({name:"yaoyao"})
setForm({
...form,
name:"miraculous"
})
受控表单绑定
- 使用React组件的状态(useState)控制表单的状态
- 准备一个React状态值
const [value,setValue] = useState('')
- 通过value属性绑定状态,通过onChange属性绑定状态同步的函数
<input type="text" value={value} onChange={(e)=>{setValue(e.target.value)}}>
React中获取DOM元素
- 在React组件中获取/操作DOM元素,需要使用useRef钩子函数,分为两步:
- 使用useRef创建ref对象,并与JSX绑定
const inputRef = useRef(null)
<input type="text" ref={inputRef}></input>
- 在DOM可用时,通过inputRef.current拿到DOM对象
const showDOM = ()=>{ console.log(inputRef); }
注意:渲染完毕之后,DOM生成之后才能进行使用
组件通信
理解组件通信
- 组件通信就是组件之间的数据传递,根据组件嵌套关系的不同,有不同的通信方法
父传子
实现步骤:
- 父组件传递数据:在子组件标签上绑定属性
- 子组件接收数据:子组件通过props参数接收数据
//定义一个子组件
const Son = (props)=>{
return <div>this is son {props.content}</div>
}
function App() {
//向子组件传递的参数
const content = "this is father"
return (
<div className="App">
<Son content={content} />
</div>
);
}
props说明
- props可传递任意的数据:数字、字符串、布尔值、数组、对象、函数、JSX
- props是只读对象:子组件只能读取props中的数据,不能直接进行修改,父组件的数据只能由父组件修改
特殊的prop children
- 当我们把内容嵌套在子组件的标签中,父组件会自动在名为children的prop属性中接收该内容
子传父
- 核心思路:在子组件中调用父组件中的函数并传递参数
//定义一个子组件
const Son = ({onGetSonMsg})=>{
const msg = "this is son msg"
return <div>this is son
<button onClick={()=>onGetSonMsg(msg)}>send msg</button>
</div>
}
function App() {
const getMsg = (msg)=>{
console.log(msg);
}
return (
<div className="App">
<Son onGetSonMsg={getMsg}>
</Son>
</div>
);
}
使用状态提升实现兄弟组件通信
- 实现思路:借助状态提升机制,通过父组件进行兄弟组件之间的数据传递
使用Context机制跨层级组件通信
实现步骤:
- 使用createContext方法创建一个上下文对象Ctx
- 在顶层组件(App)中通过Ctx.Provider组件提供数据
- 在底层组件中通过useContext钩子函数来获取消费数据
//1. 使用createContext创建一个上下文对象
const MsgContext = createContext()
//2. 在顶层组件中通过MsgContext.provider组件提供数据
//定义一个子组件
const A = ()=>{
return (
<div>
this is A component
<B/>
</div>
)
}
const B = ()=>{
const msg = useContext(MsgContext)
return (
<div>
this is B component {msg}
</div>
)
}
function App() {
const getMsg = (msg)=>{
console.log(msg);
}
const msg = "this is app msg"
return (
<div className="App">
<MsgContext.Provider value={msg}>
this is app
<A />
</MsgContext.Provider>
</div>
);
}
useEffect
- useEffect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作,比如发送AJAX请求等
useEffect依赖项参数说明
- useEffect副作用函数的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现
function App() {
const [count,setCount] = useState(0)
useEffect(()=>{
console.log("副组件触发了");
})
const handleCount = ()=>{
setCount(count+1)
}
return (
<div className="App">
this is app
<button onClick={handleCount}>count:{count}</button>
</div>
);
}
useEffect — 清除副作用
- 在useEffect中编写的由渲染本身引起的对接组件外部的操作,也经常把它叫作副作用操作
说明:清楚副作用的函数最常见的执行时机是在组件卸载时自动执行
const Son = ()=>{
//渲染时开启一个定时器
useEffect(()=>{
const time = setInterval(() => {
console.log("定时器开始");
}, 1000);
//清除副作用
return ()=>{
clearInterval(time)
}
},[])
return <div>
son component
</div>
}
function App() {
const [show,setShow] = useState(true)
return (
<div className="App">
{show && <Son/>}
<button onClick={()=>setShow(false)}>卸载子组件</button>
</div>
);
}
自定义Hook实现
- 概念:自定义Hook是以use打头的函数,通过自定义hook函数可以用来实现逻辑的封装和复用
- 通过一个按钮控制div组件是否显示
- 本来的写法:
function App() {
const [value,setValue] = useState(true)
const qiehuan = ()=>{
setValue(!value)
}
return (
<div className="App">
{value && <div>this is div</div>}
<button onClick={qiehuan}>切换</button>
</div>
);
}
- 使用Hook进行封装之后的写法:
//自定义Hook函数
const useQiehuan = ()=>{
const [value,setValue] = useState(true)
const qiehuan = ()=>{
setValue(!value)
}
return {
value,
qiehuan
}
}
function App() {
const {value,qiehuan} = useQiehuan()
return (
<div className="App">
{value && <div>this is div</div>}
<button onClick={qiehuan}>切换</button>
</div>
);
}
封装自定义hook通用思路
- 声明一个以use打头的函数(也可以不用use,为了语义化)
- 在函数体内封装可复用的逻辑
- 把组件中用到的状态和回调函数return出去(以对象或者数组)
- 在哪个组件中要用到这个逻辑,就执行这个函数,结构出来状态和回调进行使用
React Hooks使用规则
- 只能在组件中或者其他自定义Hook函数中调用
- 只能在组件的顶层调用,不能嵌套在if for 或者其他函数中