JSX
JSX 使用 大括号{}语法
1.引号传递字符串
<!-- function App() { return ( <div className="App"> this is app {'hello'} </div> ); } ` -->
2.使用 javasript 变量
<!--
const num=100;
function App() {
return (
<div className="App">
this is app
{num}
</div>
);
}
-->`
3.函数调用和方法调用
<!--
function getName(){
return 'jack';
};
function App() {
return (
<div className="App">
{getName()}
</div>
);
}
-->
<!--
function App() {
return (
<div className="App">
{new Date().getDate()}
</div>
);
}
-->
4.使用 javasript 对象
<!--
function App() {
return (
<div className="App">
{/* {new Date().getDate()} */}
<div style={{color:'red'}}>this is div</div>
</div>
);
}
-->
JSX 实现列表渲染 map 方法
加唯一 key 属性
<!--
const list=[
{id:1001,name:'jack'},
{id:1002,name:'tom'},
{id:1003,name:'mike'}
]
function App() {
return (
<div className="App">
{/* {new Date().getDate()} */}
<div style={{color:'red'}}>列表渲染</div>
<div style={{}}>{list.map(item=><li key={item.id}>{item.name}</li>)}</div>
</div>
);
}
-->
条件渲染 逻辑与运算符·三元表达式
1.逻辑与运算符&&
适用于 1 对 1 条件渲染
2.三元表达式适用于 1 对多
三元表达式适用于 1 对多条件渲染
<!--
const flag=true;
function App() {
return (
<div className="App">
<div style={{color:'red'}}>条件渲染</div>
<div style={{}}>{flag && <span>hello</span>}</div>
<div style={{}}>{flag ? <span>true</span> :<span>false</span> }</div>
</div>
);
}
-->
复杂条件渲染
<!-- 形式1 -->
<!--
const num=1;
const getNum=()=>{
if(num===0){
return <div>我是0</div>
}
else if(num===1){
return <div>我是1</div>
}
else{
return <div>我是2</div>
}
}
function App() {
return (
<div className="App">
<div style={{color:'red'}}>复杂条件渲染</div>
<div style={{}}>{getNum()}</div>
</div>
);
}
-->
//子组件根据 ishow 属性进行条件渲染 if+return
<!-- function Show({ content, isshow }) {
if (isshow) {
return( <div >
<h3>{content}</h3>
</div>)
}
return null;
}
// 父组件
export default function Profile() {
return (
<div>
<Show
isshow={ true}
content={"你好呀"}
>
</Show>
<Show
isshow={ false}>
</Show>
</div>
);
} -->
事件绑定
on+事件名称={事件处理程序} 驼峰命名规范
<!--
const num=0;
function App() {
const addClick=()=>{
console.log(num);
}
return (
<div className="App">
<div style={{color:'red'}}>事件绑定</div>
<button onClick={addClick}>点击</button>
{/* <div style={{}}>{getNum()}</div> */}
</div>
);
}
-->
事件对象 e
<!--
function App() {
const addClick=(e)=>{
console.log("被点击了",e);
}
return (
<div className="App">
<div style={{color:'red'}}>事件绑定</div>
<button onClick={addClick}>点击</button>
{/* <div style={{}}>{getNum()}</div> */}
</div>
);
}
-->
传递自定义参数 事件绑定的位置改成箭头函数的写法
<!--
function App() {
const addClick=(name)=>{
console.log("被点击了",name);
}
return (
<div className="App">
<button onClick={ () => addClick('wyz') }>点击</button>
</div>
);
}
-->
既要参数也要事件对象
<!--
function App() {
const addClick=(name,e)=>{
console.log("被点击了",name,e);
}
return (
<div className="App">
<div style={{color:'red'}}>React</div>
<button onClick={(e)=>addClick('wyz',e)}>点击</button>
{/* <div style={{}}>{getNum()}</div> */}
</div>
);
}
-->
react组件
首字母大写的函数 箭头函数也可以
<!--
const ZuJian=()=>{
return(
<div><h1>
我是一个组件
</h1></div>
)
}
function App() {
return (
<div className="App">
<div style={{color:'red'}}>React</div>
使用组件
{/* 成对 */}
<ZuJian></ZuJian>
{/* 自闭和 */}
<ZuJian/>
</div>
);
}
-->
父与子组件之间属性传值
第一种 props 传值
<!--
### 子组件
function Avator({ person }) {
return (
<div>
<h2>Katsuko Saruhashi</h2>
<img
className="avatar"
alt={person.one}
width={70}
height={70}
/>
<ul>
<li>
<b>Profession: </b>
{ person.two}
</li>
<li>
<b>Awards: 2 </b>
({ person.three})
</li>
<li>
<b>Discovered: </b>
{ person.four}
</li>
</ul>
</div>
);
}
-->
<!--
### 父组件
export default function Gallery() {
return (
<div>
<h1>Notable Scientists</h1>
<h2>Maria Skłodowska-Curie</h2>
<img
className="avatar"
alt="Maria Skłodowska-Curie"
width={70}
height={70}
/>
<ul>
<li>
<b>Profession: </b>
physicist and chemist
</li>
<li>
<b>Awards: 4 </b>
(Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
</li>
<li>
<b>Discovered: </b>
polonium (chemical element)
</li>
</ul>
<Avator
person={
{
one: "Katsuko Saruhashi",
two: " geochemist",
three:"Miyake Prize for geochemistry, Tanaka Prize",
four:" a method for measuring carbon dioxide in seawater"
}
}
></Avator>
</div>
);
}
-->
第二种
上述 Avator 单独写一个文件并暴露,父组件文件再引用:传参注意不要忘记子组件函数声明写接收父组件的参数名称
第三种
直接将内容嵌套在标签中,通过{children}赋值到子组件
<!--
子组件
function Card({ children }) {
return (
<div className="card">
<div className="card-content">
{children}
</div>
</div>
);
}
父组件
export default function Profile() {
return (
<div>
<Card>
<h1>Photo</h1>
<img
className="avatar"
src="https://i.imgur.com/OKS67lhm.jpg"
alt="Aklilu Lemma"
width={100}
height={100}
/>
</Card>
//传的内容为 children
<Card>
<h1>About</h1>
<h4>Aklilu Lemma was a distinguished Ethiopian scientist who discovered a natural treatment to schistosomiasis.</h4>
</Card>
</div>
);
}
-->
父与子组件之间属性传值
核心思路:子组件中调用父组件的函数并传递参数 前提是父组件把函数传给子组件
<!--
//子组件
function Son({ onMsy}) {
const sonMsg = "this is son"
return (
<div>
<button onClick={()=>onMsy(sonMsg)}>子传父</button>
</div>
)
}
//父组件
export default function App() {
const getMsg = (msg) => {
console.log(msg);
}
return (
<div>
<Son onMsy={ getMsg}></Son>
</div>
)
}
-->
兄弟组件通信(状态提升)
实现思路:使用状态提升机制,通过父组件进行兄弟组件之间的数据传递
状态提升:兄弟组件使用共同的父类作为桥梁,本质是父子之间通信。
<!--
import { useState } from 'react';
import './index.css'
// 组件1,组件2是app的子组件
//组件1
function Component1({ onMsy}) {
const msg = "this is 兄弟组件"
return (
<div>
<button onClick={()=>onMsy(msg)}>兄弟组件</button>
</div>
)
}
//组件2
function Component2({onMsy2}) {
console.log("兄弟组件通信",onMsy2);
}
//父组件
export default function App() {
const [con, setCon] = useState('');
const getMsg = (msg) => {
console.log(msg);
setCon(msg);
}
return (
<div>
<Component1 onMsy={getMsg}></Component1>
<Component2 onMsy2={con}></Component2>
</div>
)
}
-->
跨组件通信--context
context 可以实现跨组件通信(可实现父与子之间通信)
父与子之间通信
<!--
import { useContext } from 'react';
import './index.css'
import { createContext } from 'react';
const ctx = createContext();
//组件1
function Component1() {
const msgs= useContext(ctx);
return (
<div>
<h1>{ msgs}</h1>
</div>
)
}
//组件2
function Component2() {
const msgs= useContext(ctx);
return (
<div>
<h2>{msgs}</h2>
</div>
)
}
//父组件
export default function App() {
const getMsg ="这个是跨组件通信"
return (
<div>
<ctx.Provider value={getMsg}>
<Component1></Component1>
<Component2></Component2>
</ctx.Provider>
</div>
)
}
-->
三步骤
1.const ctx = createContext(); 创建一个上下文对象
2.顶层组件使用 ctx.Provider 组件传递数据
3.底层组件使用 useContext(ctx)接收数据
<!--
三代之间通信
import { useContext } from 'react';
import './index.css'
import { createContext } from 'react';
const ctx = createContext();
//组件1
function Component1() {
return (
<div>
<Component2></Component2>
</div>
)
}
//组件2
function Component2() {
const msgs= useContext(ctx);
console.log(msgs);
}
//父组件
export default function App() {
const getMsg ="这个是跨组件通信"
return (
<div>
<ctx.Provider value={getMsg}>
<Component1 ></Component1>
</ctx.Provider>
</div>
)
}
-->
react 钩子 React Hook 函数 只能在顶层调用
useState 是一个 React Hook 函数,允许向组件添加一个状态变量,控制组件渲染效果
useState 的更新是异步的,这意味着它不会立即更新状态变量的值,而是将更新放在队列里在稍后时间执行
const [index, setIndex] = useState(0);
状态变量 设置函数 状态变量初始值
修改变量方法: setIndex(index+1)=>1
useState的使用
修改基本数据类型
<!-- const { useState } = require("react");
const Change = () => {
const [num,setNum] = useState(1);
return (<div>
<button onClick={()=> setNum(num+1)}>{num}</button>
</div>
)
}
export default function App(){
return (<div>
<Change></Change>
</div>
)
} -->
修改引用数据类型
使用扩展运算符展开原对象 创建一个新对象来替换整个对象 后面跟上修改的属性覆盖原对象的属性
<!-- const { useState } = require("react");
const Change = () => {
const [Person, setPerson] = useState({
name: "张三",
age:20
} );
return (<div>
<button onClick={() => setPerson({...Person,name:"王五"})}>修改名字{Person.name}</button>
<button onClick={() => setPerson({...Person,age:24})}>修改年龄{Person.age}</button>
</div>
)
}
export default function App(){
return (<div>
<Change></Change>
</div>
)
} -->
嵌套对象的更新 一定要先对内部对象进行数据更改。更改后的对象为预对象,把它加到外部对象进行数据更新,最后通过 set 对整个对象更新。
<!--
const { useState } = require("react");
const Change = () => {
const [person, setPerson] = useState({
name: 'Niki de Saint Phalle',
artwork: {
title: 'Blue Nana',
city: 'Hamburg',
image: 'https://i.imgur.com/Sd1AgUOm.jpg',
}
});
function handleClick() {
//嵌套对象的数据更改,必须先对内部对象进行更新 并赋值给一个新对象。
const newPer1 = { ...person.artwork,
title: "更新了内部对象"
}
//把更新好的内部对象 更新到外部对象上
const newPer2 = { ...person,artwork:
newPer1
}
//更新对象
setPerson(newPer2)
console.log(person);
}
return (<div>
<button onClick={handleClick}>嵌套对象更新</button>
{/* <button onClick={handleClick2}>嵌套对象更新2</button> */}
</div>
)
}
export default function App(){
return (<div>
<Change ></Change>
</div>
)
} -->
添加数组
<!-- const { useState } = require("react");
let count = 1;
const Change = () => {
const [person, setPerson] = useState([]);
const [name, setName] = useState('');
return (<div>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<button onClick={() => setPerson([...person, { id: count++, name:name }])}>添加数组</button>
<ul>
{ person.map(per => (<li key={per.id}>{per.id}{ per.name}</li>))}
</ul>
</div>
)
}
export default function App(){
return (<div>
<Change ></Change>
</div>
)
} -->
删除数组 (一一删除)
<!-- const { useState } = require("react");
const Change = () => {
const [person, setPerson] = useState([
{ id: 0, name: 'Marta Colvin Andrade' },
{ id: 1, name: 'Lamidi Olonade Fakeye'},
{ id: 2, name: 'Louise Nevelson'},
]);
return (<div>
<ul>
{person.map(per => (<li key={per.id}>{per.name}
<button onClick={() => setPerson(person.filter(item => item.id!==per.id))}>删除数组</button>
新数组id和原数组id相同的删除
</li>))}
</ul>
</div>
)
}
export default function App(){
return (<div>
<Change ></Change>
</div>
)
} -->
插入数组
slice(0,1) 左开又闭合=>提取该返回内数据 slice(1)=>返回下标 1 之后的数据(2,3,4.....)
<!-- import { useState } from 'react';
let nextId = 3;
const initialArtists = [
{ id: 0, name: 'Marta Colvin Andrade' },
{ id: 1, name: 'Lamidi Olonade Fakeye'},
{ id: 2, name: 'Louise Nevelson'},
];
export default function List() {
const [name, setName] = useState('');
const [artists, setArtists] = useState(
initialArtists
);
function handleClick() {
const insertAt = 1;
const nextArtists = [
//提取该返回内数据 后面的数据都删除了
...artists.slice(0, insertAt),
//数组添加
{ id: nextId++, name: name },
//删除下标为1(包括1)之前的数据,返回剩余
...artists.slice(insertAt)
//上述操作类似于一个数组的拼接 最后返回新数组给nextArtists
];
setArtists(nextArtists);
setName('');
}
return (
<>
<h1>Inspiring sculptors:</h1>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<button onClick={handleClick}>
Insert
</button>
<ul>
{artists.map(artist => (
<li key={artist.id}>{artist.name}</li>
))}
</ul>
</>
);
} -->
反转数组 reslove
<!-- const { useState } = require("react");
const Change = () => {
const [person, setPerson] = useState([
{ id: 0, name: 'Marta Colvin Andrade' },
{ id: 1, name: 'Lamidi Olonade Fakeye'},
{ id: 2, name: 'Louise Nevelson'},
]);
function handleClick() {
//先备份一个已经反转的数组,因为reverse() 和 sort() 方法正在改变原始数组,不能直接使用它们。
const newList = [...person];
//
setPerson(newList.reverse());
}
return (<div>
<button onClick={handleClick}>反转数组</button>
<ul>
{person.map(per => (<li key={per.id}>{per.name}
</li>))}
</ul>
</div>
)
}
export default function App(){
return (<div>
<Change ></Change>
</div>
)
} -->
useEffect 类似于 vue 的 mounted 浏览器重绘后触发
依赖项参数说明
没有依赖项 useEffect(()=>{}) 副作用:组件初始渲染执行+组件更新执行
有依赖项(空数组) useEffect(()=>{},[]) 副作用:组件初始渲染执行
传入特定依赖项 useEffect(()=>{},[count]) 副作用:组件初始渲染+依赖项变化时渲染
清除副作用 useEffect(()=> { return ()=>{} },[])
<!--
清除副作用
import { useEffect, useState } from 'react';
import './index.css'
//子组件
function Component1() {
useEffect(() => {
const dsq= setInterval(() => {
console.log("这个是定时器....");
})
//清除定时器
return () => {
clearInterval(dsq);
}
},[])
return (
<div>
<h1>这是子组件</h1>
</div>
)
}
//父组件
export default function App() {
const [status,setStatus] = useState(true);
return (
<div>
{status && < Component1/>}
<button onClick={()=>setStatus(false)}>卸载组件</button>
</div>
)
}
-->
useLayoutEffect 是 useEffect 的一个版本,它在浏览器重绘屏幕之前触发。
样式结构
常用外部导入 (行内样式 const style={color:red}对象结构 )
//index.css 文件
<!--
.foo{
color: red;
display: flex;
justify-content: center;
}
-->
//App.js 导入样式文件
<!--
import './index.css'
export default function App(){
return (<div>
<h2 className="foo">样式结构</h2>
</div>
)
} -->
综合案例 评论区
<!--
import { useEffect, useState } from 'react'
import './index.css'
export default function App() {
const [num, setNum] = useState(0);
const [list, setList] = useState([]);
const [name, setName] = useState('');
const [hover, setHover] = useState(null); //控制鼠标滑动样式隐显
const handleClick = () => {
setList([
...list,
{
id: num+1, content: name
}
])
//索引加1
setNum(num+1);
setName('')
}
const handleMouseEnter = (id) => {
setHover(id);
}
const handleMouseLeave = () => {
setHover(null);
}
return (<div>
<input
value={name}
onChange={e=>setName(e.target.value)}
/>
<button onClick={handleClick}>添加</button>
<div>
<h3>评论区</h3>
</div>
<ul>
{list.map(item => <div key={item.id}><span className={item.id===hover?'goo':'' } onMouseEnter={() => handleMouseEnter(item.id)} onMouseLeave={handleMouseLeave}>{item.content}</span>
<button onClick={()=>setList(list.filter(it=>it.id!==item.id))}>删除</button>
</div>
)}
</ul>
</div>
)
}
-->
React 获取 DOM 对象---useRef
<!--
import { useEffect, useRef, useState } from 'react'
import './index.css'
export default function App() {
const inputRef = useRef();//生成ref对象
const handleClick = () => {
//打印inputRef.current DOM详细数据
console.dir(inputRef.current);
}
return (
<div>
{/* 将ref对象绑定到DOM上 */}
<input type='text' ref={inputRef}/>
<button onClick={handleClick}>添加</button>
</div>
)
}
-->
自定义 hook(封装复用代码)
1.声明一个 use 开头的函数;
2.在函数体内封装可复用逻辑;
3.使用 return 把组件需要的回调出去(数组、对象形式);
4.在组件内使用函数
<!--
import { useState } from "react";
//自定义hook
function useTools() {
const [val, setVal] = useState(false);
const change = () => setVal(!val);
//回调
return {
val,change
}
}
const App = () => {
const {val,change }= useTools();
return (
<>
{val && (
<div>这个是自定义hook</div>
)}
<button onClick={change}>自定义</button>
</>
)
}
export default App;
-->