【React自学笔记06】React18函数式组件知识点合集1
React18函数式组件
-
基于React18新特性
-
在原有的React基础上,补充函数式组件的知识点及用法
一、React事件
-
在React中事件需要通过元素的属性来设置
-
和原生JS不同,在React中事件的属性需要使用驼峰命名法:
onclick -> onClick
onchange -> onChange
-
属性值不能直接执行代码,而是需要一个回调函数,事件触发时执行:
-
onclick="alert(123)"
-
onClick={()=>{alert(123)}}
-
onClick={clickHandler} 不要加括号,加了括号代表调用函数,我们需要的是事件触发才调用
-
-
在React中,无法通过在clickHandler函数中return false取消默认行为
-
event.preventDefault(); // 取消默认行为
-
event.stopPropagation(); // 取消事件的冒泡
-
-
事件对象event
-
React事件中同样会传递事件对象,可以在响应函数中定义参数来接收事件对象
-
React中的事件对象同样不是原生的事件对象,是经过React包装后的事件对象
-
由于对象进行过包装,所以使用过程中我们无需再去考虑兼容性问题
-
二、Props
基础用法
在组件中如果将数据全部写死,将会导致组件无法动态设置,不具有使用价值
我们希望组件数据可以由外部设置,在组件间,父组件可以通过props(属性)向子组件传递数据
父组件中可以直接在子组件标签中设置属性,作为传递的参数值
-
在函数组件中,属性props就相当于是函数的参数,可以通过参数来访问
-
可以在函数子组件的形参中定义一个props,props指向的是一个对象
-
它包含了父组件中传递的所有参数
注意:props只读不能修改
//Logs.js
import LogItem from './LogItem/logItem.js'
const Logs = () => {
// 模拟一组从服务器中拿回来的数据
const logsData = [
{
id: '001',
date: new Date(2021, 1, 20, 18, 30),
desc: '学习九阳神功',
time: 30
},
{
id: '002',
date: new Date(2022, 2, 10, 12, 30),
desc: '学习降龙十八掌',
time: 20
}
];
return (
<div className='logs'>{
logsData.map((item) => {
// return <LogItem key={item.id} date={item.date} desc={item.desc} time={item.time} />
return <LogItem {...item} />
})
}
</div >
)
}
export default Logs
//LogItem.js
import MyDate from './MyDate/MyDate.js'
import './LogItem.css'
const LogItem = (props) => {
return (
<div className='item'>
<MyDate date={props.date}/>
<div className='content'>
<h2 className="desc">{props.desc}</h2>
<div className="time">{props.time}分钟</div>
</div>
</div>
)
}
export default LogItem
import './MyDate.css'
const MyDate = (props) => {
const month = props.date.toLocaleString('zh-CN', { month: 'long' })
const day = props.date.getDate()
return (
<div className='date'>
<div className='month'>{month}</div>
<div className='day'>{day}</div>
</div>
)
}
export default MyDate
传递标签体
怎么把标签体传给card:props.className
//Card.js
import './Card.css'
const Card=(props)=>{
return (
<div className={`${props.className} card`}>{props.children}</div>
)
}
export default Card
三、State
在React中,当组件渲染完毕后(先执行),再修改组件中的变量(后执行),不会使组件重新渲染;要使得组件可以受到变量的影响,必须在变量修改后对组件进行重新渲染;这里我们就需要一个特殊变量,当这个变量被修改时,组件会自动重新渲染。
state相当于一个变量,只是这个变量在React中进行了注册,React会监控这个变量的变化,当state发生变化时,会自动触发组件的重新渲染,使得我们的修改可以在页面中呈现出来。
注意:props是传给别人用的,state是对当前组件自身的属性(state是可变的,只属于当前属性)
📌定义步骤:
-
在函数组件中,我们需要通过钩子函数,获取state;
-
使用钩子 useState() 来创建state;
-
导入包:import {useState} from "react";
-
useState()需要一个值作为参数,这个值就是state的初始值
-
该函数会返回一个数组
-
数组中第一个元素,是初始值,初始值只用来显示数据,直接修改不会触发组件的重新渲染
-
数组中的第二个元素,是一个函数,通常会命名为setXxx,这个函数用来修改state,调用其修改state后会触发组件的重新渲染(重新调用render),并且使用函数中的值作为新的state值
-
-
import { useState } from "react";
import './counter.css'
const Counter = () => {
const [counter, setCounter] = useState(1);
const addHandler = () => {
setCounter(counter + 1)
}
const minusHandler = () => {
setCounter(counter - 1)
}
return (
<div className="counter">
<h2>{counter}</h2>
<button onClick={addHandler}>+</button>
<button onClick={minusHandler}>-</button>
</div>
)
}
export default Counter
💕总结:
state实际就是一个被React管理的变量;当我们通过setState()修改变量的值时,会触发组件的自动重新渲染;只有state值发生变化时,组件才会重新渲染
当state的值是一个对象时,修改时是使用新的对象去替换已有对象
-
setUser({...user, name: '猪八戒'});
-
const newUser = Object.assign({}, user);
newUser.name = '猪八戒';
setUser(newUser);
如果直接修改旧的state对象,由于对象还是那个对象,所以不会生效
- user.name = '猪八戒';
- setUser(user);
当通过setState去修改一个state时,并不表示修改当前的state,counter的初始值并没有改变;它修改的是组件下一次渲染时state值
setState()会触发组件的重新渲染,它是异步的;调完setState组件并不是立刻调用render函数进行渲染,而是先挂载到队列中,直到代码所有都执行完成再执行队列
所以当调用setState()需要用旧state的值时,一定要注意,有可能出现计算错误的情况;为了避免这种情况,可以通过为setState()传递回调函数的形式来修改state值
const addHandler = () => {
setTimeout(() => {
setCounter((prevCounter)=>{
/*
* setState()中回调函数的返回值将会成为新的state值
* 回调函数执行时,React会将最新的state值作为参数传递
* */
return prevCounter + 1;
});
// setCounter(prevState => prevState + 1);
}, 1000);
};
只要用到之前的值就传回调
四、Ref
useRef()返回的就是一个普通的JS对象 {current:undefined},所以我们直接创建一个js对象,也可以代替useRef()
const h1Ref = {current:null};
const h1Ref = useRef(); // 创建一个容器
区别:
-
我们创建的对象,组件每次重新渲染都会创建一个新对象
-
useRef()创建的对象,可以确保每次渲染获取到的都是同一个对象
-
当需要一个对象不会因为组件的重新渲染而改变时,就可以使用useRef()
📌 获取原生的DOM对象步骤
-
1.创建一个存储DOM对象的容器
-
使用 useRef() 钩子函数
-
① React中的钩子函数只能用于函数组件或自定义钩子
-
② 钩子函数只能直接在函数组件中调用
-
-
-
2.将容器设置为想要获取DOM对象元素的ref属性
- React会自动将当前元素的DOM对象,设置为容器current属性
-
代码:
< h1 id="header" ref={h1Ref}>我是标题{count}</ h1>
h1Ref.current.innerText = '嘻嘻!';
五、受控/非受控组件
非受控组件:监听表单项的变化
-
创建三个变量,用来存储表单中的数据
-
创建一个响应函数,监听相关数据的变化
-
函数的参数为e:当前触发事件的对象,事件对象中保存了当前事件触发时的所有信息
-
event.target 执行的是触发事件的对象(DOM对象)
-
-
在React中,通常表单不需要自行提交,而是要通过React提交
-
取消表单的默认行为
-
获取表单项中的数据
-
将数据拼装为一个对象
-
//LogsForm.js
import Card from "../UI/Card"
import './LogsForm.css'
const LogsForm = () => {
let inputDate = ''
let inputDesc = ''
let inputTime = 0
const dateChangeHandler = (e) => {
inputDate = e.target.value
}
const descChangeHandler = (e) => {
inputDesc = e.target.value
}
const timeChangeHandler = (e) => {
inputTime = e.target.value
}
const formSubmitHandler=(e)=>{
e.preventDefault()
const newLog={
date:new Date(),
desc: inputDesc,
time: +inputTime
}
}
return (
<Card className="logs-form">
<form onSubmit={formSubmitHandler}>
<div className="form-item">
<label htmlFor="date">日期</label>
<input id="date" type="date" onChange={dateChangeHandler} />
</div>
<div className="form-item">
<label htmlFor="desc">内容</label>
<input id="desc" type="text" onChange={descChangeHandler} />
</div>
<div className="form-item">
<label htmlFor="time">时长</label>
<input id="time" type="number" onChange={timeChangeHandler} />
</div>
<div className="form-btn">
<button >添加</button>
</div>
</form>
</Card>
)
}
export default LogsForm
受控组件(双向绑定)
将表单中的数据存储到state中,然后将state设置为表单项value值,当表单项发生变化,state会随之变化,反之,state发生变化,表单项也会跟着改变
state提升,提升到共用组件里
//app.js
import LogsForm from './Components/LogsForm/LogsForm'
import Logs from './Components/Logs/Logs'
import Counter from './Components/Counter/Counter.js'
import { useState } from 'react';
import './app.css'
const App = () => {
// 模拟一组从服务器中拿回来的数据
const [logsData, setLogsData] = useState([
{
id: '001',
date: new Date(2021, 1, 20, 18, 30),
desc: '学习九阳神功',
time: 30
},
{
id: '002',
date: new Date(2022, 2, 10, 12, 30),
desc: '学习降龙十八掌',
time: 20
}
])
const saveLogHandler = (newLog) => {
let id = Date.now() + ''
newLog = { id, ...newLog }
setLogsData([...logsData, newLog])
}
return (
<div className='app'>
<LogsForm onSaveLog={saveLogHandler} />
<Logs logsData={logsData} />
<Counter />
</div>
)
}
export default App
//Logs.js
props.onSaveLog(newLog)
===================================================
隔一段时间看受控组件已经看不懂自己的笔记了,重新补充一下
import React, {useState} from 'react';
import Card from "../UI/Card/Card";
import './LogsForm.css';
const LogsForm = () => {
/*
* 当表单项发生变化时,获取用户输入的内容
* 非受控组件中是用let定义变量来存储表单数据的 let inputDate = '';
* 但是在受控组件中,是用useState来定义的
* */
const [inputDate, setInputDate] = useState('');
const [inputDesc, setInputDesc] = useState('');
const [inputTime, setInputTime] = useState('');
// 创建一个响应函数,监听日期的变化
const dateChangeHandler = (e) => {
// 获取到当前触发事件的对象
// 事件对象中保存了当前事件触发时的所有信息
// event.target 执行的是触发事件的对象(DOM对象)
// 在受控组件中使用setState来改变state的值,在非受控组件中使用变量赋值的方式
setInputDate(e.target.value);
};
// 监听内容的变化
const descChangeHandler = (e) => {
setInputDesc(e.target.value);
};
//监听时长的变化
const timeChangeHandler = (e) => {
setInputTime(e.target.value);
};
// 当表单提交时,汇总表单中的数据
/*
* 在React中,通常表单不需要自行提交
* 而是要通过React提交
* */
const formSubmitHandler = (e) => {
// 取消表单的默认行为
e.preventDefault();
// 获取表单项中的数据日期、内容、时长
// 将数据拼装为一个对象
const newLog = {
date: new Date(inputDate),
desc: inputDesc,
time: +inputTime
};
// 清空表单项
setInputDate('');
setInputDesc('');
setInputTime('');
console.log(newLog);
/*
* 提交表单后如何清空表单中的旧数据
* 现在这种表单,在React我们称为非受控组件
*
* 我们可以将表单中的数据存储到state中,
* 然后将state设置为表单项value值,
* 这样当表单项发生变化,state会随之变化,
* 反之,state发生变化,表单项也会跟着改变,这种操作我们就称为双向绑定
* 这样一来,表单就成为了一个受控组件
*
* */
};
return (
<Card className="logs-form">
<form onSubmit={formSubmitHandler}>
<div className="form-item">
<label htmlFor="date">日期</label>
<input onChange={dateChangeHandler} value={inputDate} id="date" type="date"/>
</div>
<div className="form-item">
<label htmlFor="desc">内容</label>
<input onChange={descChangeHandler} value={inputDesc} id="desc" type="text"/>
</div>
<div className="form-item">
<label htmlFor="time">时长</label>
<input onChange={timeChangeHandler} value={inputTime} id="time" type="number"/>
</div>
<div className="form-btn">
<button>添加</button>
</div>
</form>
</Card>
);
};
export default LogsForm;
====================================================
六、创建React项目
手动创建项目
-
创建项目,目录结构如下
-
public
-
index.html
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="root"></div> </body> </html>
-
-
src
-
App.js
const App = () => { return <h1>Hello React!</h1> } export default App;
-
index.js
import ReactDOM from "react-dom/client"; import App from "./App"; const root = ReactDOM.createRoot(document.querySelector('#root')); root.render(element);
-
-
-
进入项目所在目录,执行
npm init -y
或yarn init -y
-
安装项目依赖:
npm install react react-dom react-scripts -S
或yarn add react react-dom react-scripts
-
运行
npx react-scripts start
启动项目(初次启动需要输入y确认) -
可以配置package.json
"scripts": {
"start": "react-scripts start",
},
自动创建项目
运行 npx react-scripts start
创建npx create-react-app 项目名字
启动 npm start
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步