1、创建React项目
使用脚手架create-react-app
npx create-react-app react-demo
2、函数组件只能返回一个根元素
函数组件只能返回一个根元素,如果想要返回多个根元素,可以使用<Fragment></Fragment>
标签(等价于<></>
),这是一个虚拟标签,最终不会被渲染到页面上。
return 后面返回的标签,不管是单行还是多行,最好都要加上括号(单行不加也不会报错,多行不加会出错)。
function Example () {
return (
<>
<div className="one"></div>
<div className='two'></div>
</>
);
}
3、插值
(1)条件渲染
import logo from './logo.svg'
import './App.css'
function App() {
let flag = true
let mark = false
let divContent = null
if (mark) {
divContent = <div>true mark</div>
} else {
divContent = <div>false mark</div>
}
return (
<div className="App">
<header className="App-header">
// 直接使用logo变量、三目运算符、定义的变量
<img src={logo} className="App-logo" alt="logo" />
{flag ? <div>true flag</div> : <div>false flag</div>}
{divContent}
</header>
</div>
)
}
export default App
(2)列表渲染
import { Fragment } from 'react'
import './App.css'
function App() {
const list = ['one', 'two', 'three']
const listContent = list.map((item, index) => (
<Fragment key={index}>
<li>{item}</li>
<li>{`${item}附加内容`}</li>
</Fragment>
))
return (
<div className="App">
<div>{listContent}</div>
</div>
)
}
export default App
4、状态处理
vue实现了双向响应,数据发生变化之后,视图会自动更新。但是react在数据发生变化之后,视图并不会更新,需要我们自己更新视图。
使用useState
改变状态,更新视图。
import { Fragment, useState } from 'react'
import './App.css'
function App() {
const [list, setList] = useState(['one', 'two', 'three'])
const listContent = list.map((item, index) => (
<Fragment key={index}>
<li>{item}</li>
<li>{`${item}附加内容`}</li>
</Fragment>
))
const handleClick = () => {
// 不管是对象还是数组,都需要重新整个赋值
setList([...list, 'four'])
}
return (
<div className="App">
// 如果是对象obj,直接在{}中使用对象会报错,可以选择使用对象属性在视图上展示
<div>{listContent}</div>
<button onClick={handleClick}>点击</button>
</div>
)
}
export default App
5、DOM组件
DOM组件
和HTML
的标签很像,但是React做了一定的处理,我们可以低成本的像HTML标签那样直接使用,也可以使用一些特定的组件属性className
、style
、...展开运算符
。
<img
src={logo}
className="App-logo"
style={{ width: 100, height: 100 }}
alt="logo"
/>
也可以将style样式放在对象里
function App() {
const imgStyleObject = { width: 100, height: 100 }
return (
<div className="App">
<img src={logo} className="App-logo" style={imgStyleObject} alt="logo" />
</div>
)
}
使用jsx的展开语法
function App() {
const imgStyleObject = { width: 100, height: 100 }
const imgData = { className: 'App-logo', style: imgStyleObject }
return (
// {...imgData} 这里的{}并不是...运算符的容器,是jsx的一种语法标记,对于扩展运算符,React做了额外的处理
<div className="App">
<img src={logo} alt="logo" {...imgData} />
</div>
)
}
6、React组件
通过props传递参数,可以结合扩展运算符让DOM组件变得简洁
function Deatil ({ content }) {
return <div>{content}</div>
}
function Article({ title, detailData }) {
return (
<>
<div>{title}</div>
<Deatil {...detailData}></Deatil>
</>
)
}
function App() {
const articleDate = {
title: '标题',
detailData: {
content: '内容',
},
}
return <Article {...articleDate}></Article>
}
7、将JSX作为props传递给子组件
类似于vue中的插槽功能,将组件中间的内容传递给子组件,子组件使用children接收。
function List({ children }) {
return <>{children}</>
}
function App() {
return (
<List>
<li>1</li>
<li>2</li>
<li>3</li>
</List>
)
}
8、子组件调用父组件传递过来的事件
通过props将事件属性onActive直接传递给子组件,子组件进行调用,可以通过函数向父组件传递值。
function List({ onActive }) {
const handleClick = () => {
onActive(true)
}
return (
<>
<button onClick={handleClick}>Click me!</button>
</>
)
}
function App() {
const handleActive = (status) => {
window.alert(status)
}
return <List onActive={handleActive}></List>
}
9、同级组件之间的数据传输
可以通过父组件进行中转,也就是说将数据定义在父组件中,分别传递到两个子组件中同级组件通过父组件中转传递数据
10、Context 多级组件传值
const ctx = createContext(null);
function App() {
return (
<ctx.Provider value={1}>
<Cpn />
</ctx.Provider>
);
}
function Cpn() {
const num = useContext(ctx);
return <div>{num}</div>;
}
11、hooks
Reducer:统一管理状态的操作方式
useRef:记录组件更新之前的值
useEffect:严格模式下,Effect中的函数默认执行2次,检查组件内的函数是否是纯函数
useMemo:缓存数据
useCallback:缓存函数
mome:缓存组件,如果组件接收的props没有发生变化,就不会受到父组件更新的影响。
如果传递给组件一个函数,那么可以使用useCallback包裹这个函数,使得父组件更新时,函数不会相应的更新,导致子组件的更新同步被触发。