React(一)
文章目录
- 项目地址
- 一、创建第一个react项目
- 二、JSX语法
- 2.1 生成列表
- 2.2 大括号识别JS的表达式
- 2.3 列表循环array
- 2.4 条件判断以及假值显示
- 2.5 复杂条件渲染
- 2.6 事件处理
- 2.7 添加CSS样式
- 2.8 添加图片
- 2.9 使用Fregments返回多个根标签
- 2.10多条件渲染
- 2.11 导出子组件
- 2.12 给子组件传递多个属性
- 三、组件
- 3.1 设置组件
- 3.2 props给子组件传递参数
- 3.3 给props设置默认值
- 3.4 给子组件传递children(div的children)
- 3.5 给子组件传递事件监听
- 3.6 子组件传值给父组件
- 四、State
- 4.1修改数组的值(添加与删除)
- 4.2 给setState传参
- 4.3修改类的值(增删改)
- 4.3.1 增加
- 4.3.2 修改
- 4.3.3 删
- 五、表单处理事件
- 5.1 表单的输入和保存(双向绑定)
- 5.2 处理input,select,radio,checkbox
- 5.2.1 input
- 5.2.2 单选
- 5.2.3 下拉
- 5.2.4 多选
- 5.2.5 合并表达的多个状态
- 5.2.6 使用循环处理多个checkboxes
- 5.2.7 表单整体提交处理与重置
- 5.2.8 表单验证
- 六、使用unEffect消除副作用
- 6.1 消除副作用
- 6.2 指定useEffect的执行时机
- 6.3 清理副作用
- 6.4 在useEffect()中执行异步
- 2.3 事件绑定
- 2.2.1 给onclick绑定一个事件
- 2.2.2 获取点击事件 e
- 2.2.3 传递自定义参数
- 2.2.4 传递自定义参数+ e
- 2.5 使用循环生成内容
- 2.6 Reack Hook
- 2.6.1 State
- 2.6.2 useState 钩子函数
- 2.7 使用ref获取原生DOM对象
- 2.8 将css组件化(prop.children)
- 2.8.1 props默认传值
- 2.8.2 提取公共的css
- 2.9 监听表单的内容变化,提交表单
- 2.10 使用State保存表单数据(双向绑定)
项目地址
- 教程作者:SGG
- 教程地址:
https://www.bilibili.com/video/BV1wy4y1D7JT/?spm_id_from=333.999.0.0&vd_source=791e6deaa9c8a56b1f845a0bc1431b71
- 代码仓库地址:
- 所用到的框架和插件:
Es6+ract
prettier
- vscode设置:bracket paris
一、创建第一个react项目
- 执行创建命令,创建名为
react-basic
的项目文件
npx create-react-app react-basic
- 进入到项目的根目录,开启react服务
npm start
- 核心流程:App被引入到了
index.js
里,然后被渲染到了public/index.html
里
二、JSX语法
- JSX是react编写UI模板的方式,表示在JS里编写HTML模板解构;
- 他不是标准的js语言,浏览器本身不能识别,需要通过解析后才能在浏览器里运行;
- JSX中{}里嵌入的是表达式,有值的语句才是表达式
- 如果表达式有空,布尔值,undefined他是不会显示的
- 直接设置标签时,style必须使用对象设置
2.1 生成列表
- jsx自动将数组的元素在页面中显示
- 使用array.map方法,循环列表,添加
li
- 生成列表的时候一定要个
key
const arr = ['猪八戒', '孙悟空', '唐僧', '沙和尚'];const App = () => {return (<div className="App"><ul>{arr.map(item =><div>{item}</div>)}</ul></div>);
}
- 使用for循环或者foreach
const arr = ['猪八戒', '孙悟空', '唐僧', '沙和尚'];
const liList = [];arr.forEach(item => {item.push(<li key={item}>{item}</li>);
});
2.2 大括号识别JS的表达式
①只能识别表达式;②style必须以对象形式传入
{{}}
function App() {return (<div className="App">this is a react app{/* 使用引号传递字符串 */}{'This fxx'}{/* 识别JS变量 */}{num}{/* 函数,直接显示方法的返回值 */}{getName()}{/* 方法调用 */}{new Date().toLocaleTimeString()}{/* 使用js对象,驼峰 */}<div style = {{color: 'red', fontSize: '50px'}}> this is a red div </div></div>)
}
2.3 列表循环array
①循环列表必须给Key值;②使用map循环
const list =[{id:'1001',name:'tom'},{id:'1002',name:'jerry'},{id:'1003',name:'kitty'}
]function App() {return (<div className="App">{list.map((item)=><li key={item.id}>{item.name}</li>)}</div>)
}export default App;
2.4 条件判断以及假值显示
只能用三元运算符或者&& || ! 条件表达式;不能使用if判断
- 条件表达式:当为真,返回后面的表达式,假则返回前面的
const islogin = truefunction App() {return (<div className="App">{islogin ? <h2>欢迎回来</h2> : <h2>请登录</h2>}{islogin&&<h2>用户名:{list[0].name}</h2>}</div>)
}
- jsx会将0和NaN 显示在页面上;其他得假值则为空
2.5 复杂条件渲染
- 根据传来的listType,匹配不同的jsx的模板
const listType = 5//根据listTpye,返回不同的jsx模板
function getListType() {if (listType === 0) {return <div>单图模式</div>}else if (listType === 1) {return <div>两图模式</div>}else if (listType === 2) {return <div>多图模式</div>}else {return <div>默认模式</div>}
}
const islogin = truefunction App() {return (<div className="App">{getListType()}</div>)
}
2.6 事件处理
①改为驼峰命名;②写了
()
的话,创建时直接调用
- 给事件传参,并且返回一个立即执行的函数,也可以实现相同效果
import React from "react";const islogin = false;const handleclick = (name) => {return () => {alert(name);};
};function App() {return (<div className="App"><h1>hello world</h1><button onClick={handleclick("FXX")}>click me</button></div>);
}export default App;
- 例2:
const handleclick = () => {return () => {alert("hello world");};
};function App() {return (<div className="App"><h1>hello world</h1><button onClick={handleclick()}>click me</button></div>);
}export default App;
2.7 添加CSS样式
①引入css;②将需要添加样式的地方,添加样式的className
2.8 添加图片
①使用import先导入图片;②直接在jsx里使用{}使用;
2.9 使用Fregments返回多个根标签
- react默认只能返回一个根标签,但是使用Fregments可以返回多个
function User() {return (<Fragment><p>用户名:张三</p><p>职业:前端工程师</p></Fragment>);
}
2.10多条件渲染
- 假如,需要从网络服务器请求一组数据,请求过程显示请求中,请求成功返回数据后,显示数据,这是一个副作用的例子
function App() {const [user, setUser] = useState();useEffect(() => {//使用setTimeout模拟请求延迟,3秒后返回用户数据setTimeout(() => {setUser({name: "张三",occupation: "前端工程师",});}, 3000);}, []);if (!user) {return <div className="loading">loading...</div>;}return (<main className="container"><p>用户名:{user.name}</p><p>职业:{user.occupation}</p></main>);
}
2.11 导出子组件
- 设置 组件导出
function Menu({ children }) {return <nav>{children}</nav>;
}function Item({ children }) {return <a href="#">{children}</a>;
}//将组建导出
Menu.Item = Item;export default Menu;
- 使用子组件
function App() {return (<Menu><Menu.Item>主页</Menu.Item><Menu.Item>关于</Menu.Item><Menu.Item>联系</Menu.Item></Menu>);
}
2.12 给子组件传递多个属性
三、组件
- 独立的组件单独放在一个模块(文件夹)里
- 一个大组件和他的卫星组件,可以一起放在一个文件里的同级目录;
3.1 设置组件
- PostListItem是组件名,里面文件夹是组件的样式和jsx
index.js
: 将需要做成组件的部分放入到function内部
import "./style.css";function PostListItem() {return (<div className="post" key={blog.id}><img src={blog.author.avatar} alt="" /><div className="postContainer"><p className="postContent">{blog.content}</p><div className="postMeta"><p className="postAuthor">{blog.author.name}</p><p className="postDate">{blog.publishDate}</p></div></div></div>);
}export default PostListItem;
- 将该组件的css样式放入到
style.css
中
3.2 props给子组件传递参数
- 将需要传递的参数,值,array,类,当作参数传入组件;
<div className="postList">{microBlogs.length > 0 ? (microBlogs.map((blog, index) => (<PostListItem blog={blog} key={blog.id} />))) : (<p>暂无微博</p>)}
- 在组件中使用参数
import "./style.css";function PostListItem(props) {return (<div className="post"><img src={props.blog.author.avatar} alt="" /><div className="postContainer"><p className="postContent">{props.blog.content}</p><div className="postMeta"><p className="postAuthor">{props.blog.author.name}</p><p className="postDate">{props.blog.publishDate}</p></div></div></div>);
}export default PostListItem;
- 组件在接受props的时,除了直接传递props外,还可以使用解构来接收,这样就不需要使用
props.blog
来使用
3.3 给props设置默认值
①防止报错;②页面显示正常
- 如果我们在传递列表或者类的过程中,没有内容,可能会导致页面报错;此时,我们需要传递默认值
function PostListItem({ blog = { author: "" } }) {return (<div className="post"><img src={blog.author.avatar} alt="" /><div className="postContainer"><p className="postContent">{blog.content}</p><div className="postMeta"><p className="postAuthor">{blog.author.name}</p><p className="postDate">{blog.publishDate}</p></div></div></div>);
}
注意:需要给blog里的.属性
也设置默认值
3.4 给子组件传递children(div的children)
①通过给当前组件的props添加一个children方式,并且在组件内部,添加
<div>{children}<div>
的方式来接收这个结构;②传递结构的父组件,需要将单个标签<PostListItem/>
,改为对标签<PostListItem>children<PostListItem/>
,标签里的内容,就是children;
index.js
function PostListItem({ blog = { author: "" }, children }) {return (<div className="post"><img src={blog.author.avatar} alt="" /><div className="postContainer"><p className="postContent">{blog.content}</p><div className="postMeta"><p className="postAuthor">{blog.author.name}</p><p className="postDate">{blog.publishDate}</p></div></div><div>{children}</div></div>);
}
App.js
<div className="postList">{microBlogs.length > 0 ? (microBlogs.map((blog, index) => (<PostListItem blog={blog} key={blog.id}><a href="#">编辑</a> //这里就是children,可以是结构,也可以是其他的组件</PostListItem>))) : (<p>暂无微博</p>)}
</div>
- 此外,传递的children还可以是其他的组件
function EditAndDelete({ onEdit }) {return (<div>{/* 绑定事件 */}<a href="#" onClick={onEdit}>编辑</a>{" "}<a href="#">删除</a></div>);
}
3.5 给子组件传递事件监听
作用:让组件复用性更高
- 给组件添加事件监听,这个事件监听是父类传来的方法
//传递事件的props
function EditAndDelete({ onEdit }) {return (<div>{/* 绑定事件 */}<a href="#" onClick={onEdit}>编辑</a>{" "}<a href="#">删除</a></div>);
}
在这个文件里,我们并没有直接写onEdit
的方法,而是使用props将父类的方法传递进来.
- 在父类里定义
onEdit
的方法,这里为了简单直接用箭头函数传递
<div className="postList">{microBlogs.length > 0 ? (microBlogs.map((blog, index) => (<PostListItem blog={blog} key={blog.id}><EditAndDelete onEdit={() => console.log(blog.id)} /></PostListItem>))) : (<p>暂无微博</p>)}</div>
- 如果我们想对父类传来的
onEdit
方法进行自己的一些定制,可以先定义自己的方法,然后传递父类的onEdit
,在将自己的方法传递给onClick
事件
//传递事件的props
function EditAndDelete({ onEdit }) {//将父类传递的方法定制化,在使用function handleEdit(e) {e.preventDefault();if (onEdit) {console.log("定制了onEdit,组织了跳转");onEdit();}}return (<div>{/* 绑定事件 */}<a href="www.baidu.com" onClick={handleEdit}>编辑</a>{" "}<a href="#">删除</a></div>);
}
3.6 子组件传值给父组件
事件中只要将需要传递的参数放在子组件里的onClick方法里,并且父组件用action接受,就可以完成传递
子组件
//传递事件的props
function EditAndDelete({ onEdit }) {function handleEdit(e) {e.preventDefault();if (onEdit) {console.log("定制自己的方法,阻止了跳转");onEdit("需要给父组件传递的参数");}}return (<div>{/* 绑定事件 */}<a href="#" onClick={handleEdit}>编辑</a>{" "}<a href="#">删除</a></div>);
}
父组件
<PostListItem blog={blog} key={blog.id}><EditAndDeleteonEdit={(action) => console.log(blog.id, action)}/></PostListItem>
四、State
import {useState} from "reac";const [状态值(更改后的值), 修改状态的函数] = useState(初始值(最初的值));
- 只要给
修改状态的函数
传递新的值之后,就会显示更改后的值状态值
import React from "react";function App() {const [count, setCount] = React.useState("123123");function handleClick() {setCount("hello");}console.log("count", count);return (<div><h1>{count}</h1><button onClick={handleClick}>只更新一次</button></div>);
}export default App;
4.1修改数组的值(添加与删除)
由于数组是引用类型,所以需要修改后传入新的数组,可以使用解构,也可以直接使用赋值新的数组给
setState
- 解构
function App() {const [count, setCount] = React.useState([1, 2, 3, 4]);function handleClick() {setCount([...count, 5]);}console.log("count", count);return (<div><h1>{count}</h1><button onClick={handleClick}>更改数组</button></div>);
}
- 直接赋值给新的数组
import React from "react";function App() {const [count, setCount] = React.useState([1, 2, 3, 4]);function handleClick() {const ar = [...count];ar.push(5);setCount(ar);}
- 删除我们也只能使用filter
function handleDelete(item) {setLIst(list.filter((v) => v !== item));}
4.2 给setState传参
我们如果想在onclick里事件给setState传递参数 ,就必须使用
<button onClick={() => handleClick(100)}>更改数组</button>
4.3修改类的值(增删改)
类也是引用类型,所以修改的方式也是使用解构
4.3.1 增加
- 添加新的属性
setPerson({
...persion,
gender: 男
})
4.3.2 修改
- 修改旧的属性
setPerson({
...persion,
gender: 女
})
4.3.3 删
- 删除属性
const newPerson = {...Person};
delete newPerson.age;
setPerson(newPerson);
- 使用解构
const {age,...newPerson} = person;
setPerson(newPerson);
注意:嵌套类和嵌套数组,一定要将内部嵌套的类型解构,否则直接修改,会判定没有变化
五、表单处理事件
onInput:实时的监听输入内容
onChange:失焦后才监听内容
5.1 表单的输入和保存(双向绑定)
- 我们需要获取用户的输入
function handleUserInput(e) {console.log(e.target.value);}<textareaonChange={handleUserInput}></textarea>
- 点击发布,获取用户的输入,这里使用State来保存用户输入
//定义state保存用户的值,默认值为空const [microBlog, setMicroBlog] = useState("");function handlePublish() {console.log(microBlog);}
- 当用户写了新的内容后,获取用户最新的值
function handleUserInput(e) {setMicroBlog(e.target.value);}
- 发布后,将输入框的内容清空
①设置清空
function handlePublish() {console.log(microBlog);setMicroBlog(" ")}
②将清空后的State的值,放入到text的value里,这样当最后一次清空了状态,状态值会显示在value里
<div className="publishBlog"><textareaonChange={handleUserInput}value={microBlog}placeholder="写点什么吧..."></textarea><button onClick={handlePublish}>发布</button></div>
- 将刚才获取到的用户输入内容,组装成为一个新的对象
function handlePublish() {// console.log(microBlog);const newMicroBlog = {id: microBlogs.length + 1,author: {name: "张小丰",avatar: UserImage1,},content: microBlog,publishDate: new Date().toISOString().split("T")[0],};}
- 使用State将新组建的数组存储起来:
①将之前的数据放入到一个新的state里
const [microBlogs, setMicroBlogs] = useState([{id: 1,author: {name: "张小丰",avatar: UserImage1,},content:"这是一条微博信息,今天的天气真不错啊,出去玩啊?你们觉得怎么样?要不下午4 点出去?",publishDate: "2022-10-25",}]);
②使用解构,将新的实例存储起来
function handlePublish() {// console.log(microBlog);const newMicroBlog = {id: microBlogs.length + 1,author: {name: "张小丰",avatar: UserImage1,},content: microBlog,publishDate: new Date().toISOString().split("T")[0],};setMicroBlogs([...microBlogs, newMicroBlog]);}
5.2 处理input,select,radio,checkbox
5.2.1 input
- input标签
<label htmlFor="password">密码</label>
<input type="text" id="username" value={username} onChange={handleUsernameChange} />
- 设置state
const [username, setUsername] = useState("");function handleUsernameChange(e) {setUsername(e.target.value);}
5.2.2 单选
- 单选:通过
checked={gender === "male"}
来判断是否选择
<fieldset id="gender"><input type="radio" id="male" name="gender" value="male" checked={gender === "male"} onChange={handleGenderChange} /><label htmlFor="male">男</label>
5.2.3 下拉
- 单选
<label htmlFor="occupation">职业</label><select id="occupation" value={occupation} onChange={handleOccupationChange} ><option value="">请选择</option><option value="frontend">前端</option><option value="backend">后端</option><option value="fullstack">全栈</option></select>
5.2.4 多选
多选的State和上面3个不一样,因为他涉及了array的添加和删除
function handleHobbiesChange(e) {const { checked, value } = e.target;if (checked) {setHobbies([...hobbies, value]);} else {setHobbies(hobbies.filter((hobby) => hobby !== value));}}
- 标签里添加name属性,用于之后状态的判断,并修改为统一的handleHobbiesChange
<fieldset id="hobbies"><input type="checkbox" name="hobby" value="programming" id="programming" onChange={handleHobbiesChange} checked={hobbies.includes("programming")}/><label htmlFor="programming">编程</label><input onChange={handleHobbiesChange} checked={hobbies.includes("drawing")}/></fieldset>
- 根据name属性,更新事件
function handleInputChange(e) {let { value, name, type } = e.target;if (type === "checkbox") {const { checked } = e.target;if (checked) {value = [...user.hobbies, value];} else {value = user.hobbies.filter((hobby) => hobby !== value);}}setUser({...user,[name]: value,});}
5.2.5 合并表达的多个状态
- 定义统一的状态,放在一个实例中
const [user, setUser] = useState({username: "",password: "",repeatPassword: "",gender: "",occupation: "",hobbies: [],});
- 合并事件处理函数
function handleInputChange(e) {let { value, name, type } = e.target;if (type === "checkbox") {const { checked } = e.target;if (checked) {value = [...user.hobbies, value];} else {value = user.hobbies.filter((hobby) => hobby !== value);}}setUser({...user,[name]: value,});}
- 给标签添加name的属性,用来判断
<label htmlFor="username">用户名</label><input name="username" type="text" id="username" value={user.username} onChange={handleInputChange} />
5.2.6 使用循环处理多个checkboxes
- 将多个复选框不同的地方放在一个数组中,循环数组
const hobbies = [{ value: "programming", label: "编程" },{ value: "drawing", label: "绘画" },{ value: "music", label: "音乐" },];<fieldset id="hobbies">{hobbies.map((hobby) => (<Fragment><inputtype="checkbox"name="hobbies"value={hobby.value}id={hobby.value}onChange={handleInputChange}checked={user.hobbies.includes(hobby.value)}/><label htmlFor={hobby.value}>{hobby.label}</label></Fragment>))}</fieldset>
5.2.7 表单整体提交处理与重置
- 在form标签上添加事件处理
<form onSubmit={handleFormSubmit}>
- 将提交的表单数据保存
function handleFormSubmit(e) {e.preventDefault();console.log(user);}
- 给form添加一个onReset事件
<form onSubmit={handleFormSubmit} onReset={handleFormReset}>
重置
4. 设置表单的初始状态
const initialUser = {username: "",password: "",repeatPassword: "",gender: "",occupation: "",hobbies: [],};const [user, setUser] = useState(initialUser);
- 事件监听useState
function handleFormReset() {setUser(initialUser);}
5.2.8 表单验证
- 创建一个状态来存储表达的错误
const [formErrors, setFormErrors] = useState({});
- 定义校验规则
const rules = {username: (value) => {if (value.length < 3 || value.length > 12) {return "用户名必须大于 3 且小于 12 个字符";}},password: (value) => {if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/.test(value)) {return "密码必须大于 8 个字符,且至少包含一个字母和数字";}},};
- 保存错误信息
const error = rules[name] && rules[name](value);setFormErrors({...formErrors,[name]: error,});}
- 修改页面,添加错误显示
{formErrors.username && (<span className="formError">{formErrors.username}</span>)}
- 在提交表单时,验证错误信息是否消除
function handleFormSubmit(e) {e.preventDefault();for (let rule of Object.keys(rules)) {const error = rules[rule](user[rule]);if (error) {setFormErrors({...formErrors,[rule]: error,});return;}}console.log(user);}
六、使用unEffect消除副作用
组件发生监听事件,网络请求,设置定时器,在Reac当中就是组件副作用
6.1 消除副作用
设置定时器,网络请求,各种异步操作都在useEffect里执行
useEffect(() => {const id = setInterval(() => {setDateTime(new Date());}, 1000);console.log(id);}, []);
6.2 指定useEffect的执行时机
- 给
[]
内添加处触发的事件:当refresh的状态发生改变,触发useEffect
function App() {const [dateTime, setDateTime] = useState(new Date());const [refresh, setRefresh] = useState(0);useEffect(() => {setDateTime(new Date());}, [refresh]);return (<main className="container"><h1>{dateTime.toLocaleString("zh-CN")}</h1><button onClick={() => setRefresh(refresh + 1)}>刷新</button></main>);
}
6.3 清理副作用
function App() {const [dateTime, setDateTime] = useState(new Date());const [refresh, setRefresh] = useState(0);useEffect(() => {const id = setInterval(() => {setDateTime(new Date());}, 1000);console.log(id);//清理副作用return () => {clearInterval(id);console.log("清理了 id 为" + id + "的 interval");};}, []);useEffect(() => {setDateTime(new Date());}, [refresh]);return (<main className="container"><h1>{dateTime.toLocaleString("zh-CN")}</h1><button onClick={() => setRefresh(refresh + 1)}>校准</button></main>);
}
6.4 在useEffect()中执行异步
- 需要将异步方法先定义成为一个函数,然后再useEffect里调用
function App() {const [dateTime, setDateTime] = useState(new Date());useEffect(() => {updateTime();}, []);async function updateTime() {await new Promise((resolve) => setTimeout(resolve, 3000));setDateTime(new Date());}return (<main className="container"><h1>{dateTime.toLocaleString("zh-CN")}</h1></main>);
}
2.3 事件绑定
- react中取消默认行为
e.preventDefault()
2.2.1 给onclick绑定一个事件
- 给鼠标的onclick事件绑定一个方法
const handleclick = () => {alert('hello world')
}function App() {return (<div className="App"><h1>hello world</h1><button onClick={handleclick}>click me</button></div>)
}export default App;
2.2.2 获取点击事件 e
- 获取点击事件
e
const handleclick = (e) => {return console.log(e)
}
2.2.3 传递自定义参数
- 传递自定义参数
- 注意onClick后面的写法,必须使用箭头函数,延迟执行;如果直接传参调用,会在button创建的时候直接执行;
const handleclick = (name) => {return console.log(name)
}function App() {return (<div className="App"><h1>hello world</h1><button onClick={()=>handleclick('fxx')}>click me</button></div>)
}
2.2.4 传递自定义参数+ e
- 既传递自定义参数,也传递点击事件 e
const handleclick = (name,e) => {return console.log(name,e)
}function App() {return (<div className="App"><h1>hello world</h1><button onClick={(e)=>handleclick('fxx',e)}>click me</button></div>)
}
2.5 使用循环生成内容
- 这里是手动添加的循环,实际我们需要模拟服务端来的数据;
- 模拟服务端的数据
const notBookJson = [{content: "学习英语",stuTime: 1500,month: "11月",day: 14,},{content: "阅读英文书籍",stuTime: 1200,month: "10月",day: 20,},{content: "练习听力",stuTime: 800,month: "9月",day: 5,},{content: "背诵单词",stuTime: 600,month: "11月",day: 1,},
];
- 使用map循环数据
const addData = notBookJson.map((item) => (<NoteItemskey={item.id}content={item.content}stuTime={item.stuTime}month={item.month}day={item.day}/>
))const NoteBook = () => {return (<div className="logs">{addData}</div>);
};export default NoteBook;
2.6 Reack Hook
- React中的钩子函数只能用于函数组件或者自定义钩子中
- 钩子函数只能在函数组件内部调用,不能再外部调用
2.6.1 State
- State是组件本身的状态,不能传递给其他组件;State是可变的,当Stage发生变化,会自动对该组件进行刷新,所以必须写在组件顶部;
- 在函数组件中,我们需要使用hook函数,获取State的;
2.6.2 useState 钩子函数
useState()
:
- 返回一个数组,第一个值是我们传递的值(字符串,array,function,class都可以);
- 第二个值是函数,通常命名为
setXXXX
,调用该函数setCounter(新值)
,修改state后,会触发组件重新渲染;并且将传入该函数的值,当作新的counter;- 改的并不是当前的值,而是下一次渲染的值
- setState()他是异步渲染,当我们调用它,需要用旧的值时,会出现计算错误;为了避免这种情况,我们可以通过回调函数来设置setState();
const flag = 1
const [counter, setCounter] = useState(flag)
- 点击按钮,页面数字翻倍
import "./App.css";
import React, { useState } from "react";function App() {//设置一个初始状态,初始值为12,返回初始值和一个const [valueAdd1, setCount] = useState(12);//定义一个点击事件,每次点击给const handleClick = () => {setCount(valueAdd1 *2);};return (<div className="App"><button onClick={handleClick}>点击我,初始值+1</button><div className="showValue">{valueAdd1}</div></div>);
}export default App;
2.7 使用ref获取原生DOM对象
了解
2.8 将css组件化(prop.children)
- 该方案是将公共的css属性,放在一个div里,让这个div成为他们的父类
2.8.1 props默认传值
当组件中存在嵌套内容时,React 会自动将标签的内容,属性传递给
props
const NoteBook = () => {return (<Card className="logs" style='fontSize:12px'>{addData}</Card>);
};
- Card.js
function Card(props) {console.log(props)return (// <div className={'card ' + props.className}><div className={`card ${props.className}`}>{props.children}</div>)
}
- 在控制台看到,className, 所有的属性,已经标签的内容(这里是
{addData}
的列表) 都被当作了默认的数值传到了props
里
2.8.2 提取公共的css
- 我们将卡片的公共的css提取到
Card.css
里
.card{border-radius: 10px;box-shadow: 0 0 10px rgba(0,0,0,0.2);
}
- 给盒子的外部,添加一个
card
的类名,这样就拥有了card以及原来的类的样式
const NoteBook = () => {return (<Card className="logs" style='fontSize:12px'>{addData}</Card>);
};
2.9 监听表单的内容变化,提交表单
在React中,通常表单不需要自行提交,而是通过React提交;
- 创建一个监听的事件
// 1. 创建一个响应函数,监听表单的变化const descChangeHandler = (e) => {console.log(e.target.value);inputDate = e.target.value;}//2.监听date的变化 const dateChangeHandler = (e) => {console.log(e.target.value);inputeDate = e.target.value}
- 给表单添加onChage方法:添加监听
onChange
<div><label htmlFor="desc">内容</label><input onChange={descChangeHandler} id="date" type="text" /></div><div><label htmlFor="desc">内容</label><input onChange={descChangeHandler} id="date" type="text" /></div>
- 将提交信息赋值:将上面监听到信息赋值给变量
let inputDate = ' ';
let inputDesc = '' ;
- 监听form的提交:给form的添加一个onSubmit的方法,监听他的提交
<form onSubmit={formSubmitHandler}>
- 提交表单:取消表单的默认提交刷新的功能,将上面赋值的数据拼接成一个对象,传递给react
const formSubmitHandler = (e) =>{e.preventDefault();const newLog = {date:new Date(inputDate),desc: inputDesc}
}
2.10 使用State保存表单数据(双向绑定)
- 将上面3的步骤改为State存储数据
const [inputeDate,setInputDate] = useState()
const [inputeDesc,setInputDesc] = useState()
- 将表单的
e.target.value
直接传给setInputDesc
// 1. 创建一个响应函数,监听表单的变化const descChangeHandler = (e) => {setInputDesc(e.target.value);}
- 将表单的input里的value改为State的监控对象,这样只要值发生了变化,就会传递react
<div><label htmlFor="desc">内容</label><input onChange={descChangeHandler} id="date" value={inputeDesc} type="text" /></div><div><label htmlFor="desc">内容</label><input onChange={descChangeHandler} id="date" value={inputeDate} type="text" /></div>
- 当提交结束是,将setState的内容清空
const formSubmitHandler = (e) =>{e.preventDefault();const newLog = {date:new Date(inputDate),desc: inputDesc}setInputDate(' ');setInputDesc(' ');
}
- 完整代码:
import React from "react";
import Card from "../UI/Cards/Card";
import "./LogsForm.css";
import { useState } from "react";function LogsForm(props) {//1.定义两个表达Stateconst [inputDate,setInputDate] = useState();const [inputDesc,setInputDesc] = useState();//2.监听表达的input的变化const descChangeHandler = (e) => {setInputDesc(e.target.value);}//2.监听表达的input的变化 const dateChangeHandler = (e) => {setInputDate(e.target.value); } //3.监听表单的提交const formSubmitHandler = (e) =>{e.preventDefault();const newLog = {date:new Date(inputDate),desc: inputDesc}console.log(newLog);setInputDate('');setInputDesc('');}return (<Card className="logs-form">{/* 给表单的提交添加一个监听事件 */}<form onSubmit={formSubmitHandler}><div className="form-item"><label htmlFor="date">日期</label>{/* 将表单的value值设置为inputDate */}<input onChange={dateChangeHandler} id="date" value={inputDate} type="date" /></div><div><label htmlFor="desc">内容</label><input onChange={descChangeHandler} id="date" value={inputDesc} type="text" /></div><div><label htmlFor="time">时长</label><input id="time" type="number" /></div><div><button>添加</button></div></form></Card>);
}export default LogsForm;
相关文章:

React(一)
文章目录 项目地址一、创建第一个react项目二、JSX语法2.1 生成列表2.2 大括号识别JS的表达式2.3 列表循环array2.4 条件判断以及假值显示2.5 复杂条件渲染2.6 事件处理2.7 添加CSS样式2.8 添加图片2.9 使用Fregments返回多个根标签2.10多条件渲染2.11 导出子组件2.12 给子组件…...

Liunx-Ubuntu22.04.1系统下配置Anaconda+pycharm+pytorch-gpu环境配置
这里写自定义目录标题 Liunx-Ubuntu22.04.1系统下配置Anacondapycharmpytorch-gpu环境配置一、Anaconda3配置1.Anaconda安装2.Anaconda更新3.Anaconda删除 二、pycharm配置1.pycharm安装 三、pytorch配置 Liunx-Ubuntu22.04.1系统下配置Anacondapycharmpytorch-gpu环境配置 一…...

Postman之数据提取
Postman之数据提取 1. 提取请求头\request中的数据2. 提取响应消息\response中的数据3. 通过正在表达式提取4. 提取cookies数据 本文主要讲解利用pm对象对数据进行提取操作,虽然postman工具的页面上也提供了一部分的例子,但是实际使用时不是很全面&#…...

selenium元素定位校验以及遇到的元素操作问题记录
页面元素定位方法及校验 使用比较多的是通过id、class和xpath来对元素进行定位。在定位前可以现在浏览器验证是否可以找到指定的元素。这样就不用每添加一个元素定位都运行代码来检查定位方式表达式是否正确。 使用XPATH定位 在浏览器F12,找到元素,在元…...

在AndroidStudio中新建项目时遇到的Gradle下载慢问题,配置错的按我的来,镜像地址不知道哪个网页找的,最主要下载要快
android-studio-2024.2.1.11-windows Android 移动应用开发者工具 – Android 开发者 | Android Developers https://r4---sn-j5o76n7z.gvt1-cn.com/edgedl/android/studio/install/2024.2.1.11/android-studio-2024.2.1.11-windows.exe?cms_redirectyes&met1731775…...

用mv命令替换rm命令
# 用mv命令替换rm命令 主要内容来源自以上博文 rm命令穷凶极恶,以下为替换命令的方式,必做 步骤 修改vim ~/.bashrc加入以下代码 mkdir -p ~/.trash #在家目录下创建一个.trash文件夹(隐藏文件,ls -a 查看) alias rmdel #使用别名…...

电解车间铜业机器人剥片技术是现代铜冶炼过程中自动化和智能化的重要体现
电解车间铜业机器人剥片技术是现代铜冶炼过程中自动化和智能化的重要体现 电解车间铜业机器人剥片技术是现代铜冶炼过程中自动化和智能化的重要体现,它主要应用于铜电解精炼的最后阶段,即从阴极板上剥离出纯铜的过程。以下是该技术的几个关键点ÿ…...

【qt】控件2
1.frameGeometry和Geometry区别 frameGeometry是开始从红圈开始算,Geometry从黑圈算 程序证明:使用一个按键,当按键按下,qdebug打印各自左上角的坐标(相当于屏幕左上角),以及窗口大小 Widget::Widget(QWid…...

Frida反调试对抗系列(四)百度加固
本文只是交流技术,如有侵权请联系我删除。 知识星球:https://t.zsxq.com/kNlj4 前言: 上一篇文章我们提到 我们使用github开源魔改好的frida server 但是仍然有一些厂商的server不能通过,那么这篇文章针对百度加固 进行快速通…...

Redis 安全
Redis 安全 Redis是一个开源的,高性能的键值存储系统,它通常被用作数据库,缓存和消息代理。由于其高性能和简单的API,Redis在全球范围内被广泛使用。然而,与其他数据库系统一样,Redis的安全性也是至关重要…...

上交大与上海人工智能研究所联合推出医学多语言模型,模型数据代码开源
今天为大家介绍的是来自上海交通大学的王延峰与谢伟迪团队的一篇论文。开源的多语言医学语言模型的发展可以惠及来自不同地区、语言多样化的广泛受众。 来源丨 DrugAI、 机器人的脑电波 论文:https://www.nature.com/articles/s41467-024-52417-z MMedC࿱…...

网络安全:我们的安全防线
在数字化时代,网络安全已成为国家安全、经济发展和社会稳定的重要组成部分。网络安全不仅仅是技术问题,更是一个涉及政治、经济、文化、社会等多个层面的综合性问题。从宏观到微观,网络安全的重要性不言而喻。 宏观层面:国家安全与…...

理解 Python 中的 __getitem__ 方法:在自定义类中启用索引和切片操作
理解 Python 中的 __getitem__ 方法:在自定义类中启用索引和切片操作 在Python中,__getitem__是一个特殊方法,属于数据模型方法之一,它使得Python对象能够支持下标访问和切片操作。这个方法提供了一种机制,允许类的实…...

【数据结构】【线性表】【练习】反转链表
申明 该题源自力扣题库19,文章内容(代码,图表等)均原创,侵删! 题目 给你单链表的头指针head以及两个整数left和right,其中left<right,请你反转从位置left到right的链表节点&…...

vue2+3 —— Day5/6
自定义指令 自定义指令 需求:当页面加载时,让元素获取焦点(一进页面,输入框就获取焦点) 常规操作:操作dom “dom元素.focus()” 获取dom元素还要用ref 和 $refs <input ref"inp" type&quo…...

汽车资讯新视角:Spring Boot技术革新
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...

关于win11电脑连接wifi的同时,开启热点供其它设备连接
背景: 我想要捕获手机流量,需要让手机连接上电脑的热点。那么问题来了,我是笔记本电脑,只能连接wifi上网,此时我的笔记本电脑还能开启热点供手机连接吗?可以。 上述内容,涉及到3台设备&#x…...

【Apache Paimon】-- 2 -- 核心特性 (0.9.0)
目录 1、实时更新 1.1、实时大批量更新 1.2、支持定义合并引擎 1.3、支持定义更新日志生成器 2、海量数据追加处理 2.1、append table 2.2、快速查询 3、数据湖功能(类比:hudi、iceberg、delta) 3.1、支持 ACID 事务 3.2、支持 Time…...

golang对日期格式化
1.对日期格式化为 YYYY-mm-dd, 并且没有数据时,返回空 import ("encoding/json""time" )type DateTime time.Timetype SysRole struct {RoleId int64 gorm:"type:bigint(20);primary_key;auto_increment;角色ID;" json:&quo…...

【数据结构与算法】排序
文章目录 排序1.基本概念2.分类2.存储结构 一.插入排序1.1直接插入排序1.2折半插入排序1.3希尔排序 二.选择排序2.1简单选择排序2.2堆排序 三.交换排序3.1冒泡排序3.2快速排序 四.归并排序五.基数排序**总结** 排序 1.基本概念 排序(sorting)又称分类&…...

前端常见的几个包管理工具详解
文章目录 前端常见的几个包管理工具详解一、引言二、包管理工具详解1、npm1.1、npm的安装与使用 2、yarn2.1、yarn的安装与使用 3、pnpm3.1、pnpm的安装与使用 三、步骤二4、包管理工具的选择 四、总结优缺点对比 前端常见的几个包管理工具详解 一、引言 在前端开发的世界里&…...

PyAEDT:Ansys Electronics Desktop API 简介
在本文中,我将向您介绍 PyAEDT,这是一个 Python 库,旨在增强您对 Ansys Electronics Desktop 或 AEDT 的体验。PyAEDT 通过直接与 AEDT API 交互来简化脚本编写,从而允许在 Ansys 的电磁、热和机械求解器套件之间无缝集成。通过利…...

腾讯云存储COS上传视频报错
bug表现为:通过COS上传视频时报错"Class \"QCloud\\COSSTS\\Sts\" not found" 修复办法为:找到文件crmeb/services/upload/storage/Cos.php 将Sts引入由QCloud\COSSTS\Sts;改为crmeb\services\upload\extend\cos\Sts; 修改后重启服…...

Tomcat(17) 如何在Tomcat中配置访问日志?
在Apache Tomcat中配置访问日志是一个重要的步骤,它可以帮助你跟踪和分析服务器的HTTP请求。访问日志通常记录了每个请求的详细信息,如客户端IP地址、请求时间、请求的URL、HTTP状态码等。以下是如何在Tomcat中配置访问日志的详细步骤和代码示例。 步骤…...

根据频繁标记frequent_token,累加size
根据频繁标记frequent_token,累加size for k, v in contents.items(): 0 (LDAP Built with OpenLDAP LDAP / SDK, /:=@) 1 (LDAP SSL support unavailable, :) 2 (suEXEC mechanism enabled lili wrapper /usr/sbin/suexec, ()/:) 3 (Digest generating secret for digest au…...

2、计算机网络七层封包和解包的过程
计算机网络osi七层模型 1、网络模型总体预览2、数据链路层4、传输层5.应用层 1、网络模型总体预览 图片均来源B站:网络安全收藏家,没有本人作图 2、数据链路层 案例描述:主机A发出一条信息,到路由器A,这里封装目标MAC…...

无人机飞手入门指南
无人机飞手入门指南旨在为初学者提供一份全面的学习路径和实践建议,帮助新手快速掌握无人机飞行技能并了解相关法规知识。以下是一份详细的入门指南: 一、了解无人机基础知识 1. 无人机构造:了解无人机的组成部分,如机身、螺旋桨…...

Redis与IO多路复用
1. Redis与IO多路复用概述 1.1 Redis的单线程特性 Redis是一个高性能的键值存储系统,其核心优势之一便是单线程架构。在Redis 6.0之前,其所有网络IO和键值对的读写操作都是由一个主线程顺序串行处理的。这种设计简化了多线程编程中的锁和同步问题&…...

基于Java和Vue实现的上门做饭系统上门做饭软件厨师上门app
市场前景 生活节奏加快:在当今快节奏的社会中,越来越多的人因工作忙碌、时间紧张而无法亲自下厨,上门做饭服务恰好满足了这部分人群的需求,为他们提供了便捷、高效的餐饮解决方案。个性化需求增加:随着人们生活水平的…...

spi 回环
///tx 极性0 (sclk信号线空闲时为低电平) /// 相位0 (在sclk信号线第一个跳变沿进行采样) timescale 1ns / 1ps//两个从机 8d01 8d02 module top(input clk ,input rst_n,input [7:0] addr ,input …...