1.创建项目
npx create-react-app demo
cd demo
npm start // 启动
2.组件化开发
import ReactDOM from "react-dom";
import App from "./App"; // 引入组件
ReactDOM.render(
<App />
document.getElementById("root"),
);
import React from 'react'
export default function app11() {
return (
<div>你好</div>
)
}
小结
- 1.文件名可以是jsx或者js,不影响文件中的代码
- 2.组件名称必须大写
- 3.JS中出现()代表其中想要写html
- 4. HTML中出现{}代表其申相要写is
- 5.其实export default也可以写到class前面
- if判断三元运算、for循环使用map
3.state完整写法和方法的调用
import React, {Component} from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
num: 1
}
this.add = this.add.bind(this)
}
render() {
return (
<>
<h2>数字:{this.state.num}</h2>
{/* 更新state */}
<button onClick={()=> this.setState({num: this.state.num++})}></button>
{/* 第二种 */}
<button onClick={this.add}></button>
{/* 第三种 */}
<button onClick={()=> this.add()}></button>
{/* 第四种 */}
<button onClick={this.add.bind(this)}></button>
</>
)
}
add() {
this.setState({num: this.state.num++})
}
}
4.函数式组件
export default function App() {
return <h2></h2>
}
特点:
- 函数式组件没有生命周期
- 函数式组件没有this
- 函数式组件没有state状态
5.hook-useState
import { useState } from "react"
const App = () => {
const [a, setA] = useState(1)
return (
<>
<h2>{a}</h2>
<button onClick={()=>{setA(2)}}>按钮</button>
</>
)
}
export default App
6.hook-useEffect
import { useState, useEffect } from "react"
const App = () => {
const [a, setA] = useState(1)
// 模拟 mounted
useEffect(() => {
console.log(‘挂在完成’)
})
// 模拟 updated
// 1.检测那个值就把那个值放到数组中
// 2.检测页面中所有变量删掉数组
// 3.不想检测任何数据,给个空数组
useEffect(() => {
console.log(‘a更新了’)
}, [a])
// 模拟 beforDestroy
useEffect(() => {
return () => {
console.log(‘页面销毁前’)
}
})
return (
<>
<h2>{a}</h2>
<button onClick={()=>{setA(2)}}>按钮</button>
</>
)
}
export default App
7.父传子
// 孙子组件
function Child(props) {
return <h2>子组件 - {props.num}</h2>
}
// 父组件
function Father(props){
return <Child num={props.num} />
}
// 顶级组件
export default function App1() {
return <Father num={456} />
}
8.子传父
// 孙子组件
function Child(props) {
return (
<>
<h2>{props.num}</h2>
<button onClick={()=>{ props.setNum(456) }}>按钮</button>
</>
)
}
// 父组件
function Father(props){
return <Child num={props.num} setNum={props.setNum} />
}
// 顶级组件
export default function App() {
const [num, setNum] = useState(123)
return <Father num={num} setNum={props.setNum} />
}
9.hook-createContext跨级组件传值
import { createContext, useState } from 'react'
// 创建上下文空间(Provider提供器,Consumer消费者)
const NumContext = createContext()
// 孙子组件
function Child(props) {
return (
<NumContext.Consumer>
{
({num, setNum}) => (
<>
<h2>{num}</h2>
<button onClick={()=>{ setNum(456) }}>按钮</button>
</>
)
}
</NumContext.Consumer>
)
}
// 父组件
function Father(props) {
return (<Child />)
}
// 顶级组件
export default function App() {
const [num, setNum] = useState(123)
return (
<NumContext.Provider value={{num, setNum}}>
<Father />
</NumContext.Provider>
)
}
10.hook-useContext
import { createContext, useState, useContext } from 'react'
// 创建上下文空间(Provider提供器,Consumer消费者)
const NumContext = createContext()
// 孙子组件
function Child(props) {
const {num, setNum} = useContext(NumContext)
return (
<>
<h2>{num}</h2>
<button onClick={()=>{ setNum(456) }}>按钮</button>
</>
)
}
// 父组件
const Father = () => <Child />
// 顶级组件
export default function App() {
const [num, setNum] = useState(123)
return (
<NumContext.Provider value={{num, setNum}}>
<Father />
</NumContext.Provider>
)
}
11.受控组件和非受控组件 模仿v-model
import { useState, useRef } from 'react'
export default function App() {
const [a, setA] = useState('')
const ele = useRef(null)
return (
<div>
<h2>受控组件-{a}</h2>
<input type="text" value={a} onChange={(e)=> { setA(e.target.value) }} />
<h2>不受控组件-{a}</h2>
<input type="text" ref={ele} />
<button onClick={()=> {console.log(ele.current.value)}}>获取</button>
</div>
)
}
- 受控组件只存在于表单元素
- 受控组件就是表单元素的value,需要通过state(或useState)来定义
- 不受控组件就是表单元素的value无法通过state获取,只能使用ref(或useRef)来获取
12.hook-memo
import { useState, memo } from 'react'
const Child1 = ()=> {
console.log(‘没加memo,父组件更新,子组件也会被刷新’);
return <div>Child1</div>
}
const Child2 = memo(()=> {
console.log(‘加memo,只有页面初始化的时候才会触发一次’);
return <div>Child2</div>
})
export default function App4() {
const [num, setA] = useState(1)
return (
<div>
<h2>{num}</h2>
<button onClick={()=> setA(num+1) }>累加</button>
<Child1 />
<Child2 />
</div>
)
}
13.hook-useCallback和useMemo
import { useState, memo, useCallback, useMemo } from 'react'
const Child1 = memo((props)=> {
console.log(‘即使加了memo,点击事件放在子组件不使用useCallback,子组件还是会每次更新’);
return <button onClick={()=> props.numSet1() }>Child1累加</button>
})
const Child2 = memo(()=> {
console.log(‘使用useCallback且第二个参数给孔数组,每次点击子组件就不会更新了’);
return return <button onClick={()=> props.numSet2() }>Child2累加</button>
})
export default function App4() {
const [num, setA] = useState(1)
const numSet1 = ()=>{
setA((num)=>num+1)
}, [])
const numSet2 = useCallback(()=>{
setA((num)=>num+1)
}, [])
// useMemo 写法和useCallback类似效果一致。从函数中返回函数
const numSet2 = useMemo(()=>{
return ()=> setA((num)=>num+1)
}, [])
return (
<div>
<h2>{num}</h2>
<Child1 numSet={numSet1} />
<Child2 numSet={numSet2} />
</div>
)
}
14.React Redux安装
npm i redux react-redux --save
15.仓库与reducer创建
// 仓库的入口文件
// 引入reducer
import reducer from "./reducer";
// 创建仓库
import { createStore } from "redux";
const store = createStore(reducer);
export default store;
// 创建初试状态
const defaultState = {
num: 1,
};
// eslint-disable-next-line import/no-anonymous-default-export
export default (state = defaultState) =>
return state;
};
16.提供器与连接器
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux"; // 提供器
import store from "./store"; // 引入
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
import React from 'react'
import { connect } from 'react-redux' // 连接器
const App = (props) => {
return (
<>
<div>{props.num}</div>
</>
)
}
// 状态映射:将reducer中的state映射成props
// props.num去调用state的num
const mapStateProps = (state) => {
return {
num: state.num
}
}
// export default connect(state映射,dispatch映射)(当前组件的名字)
export default connect(mapStateProps)(App)
17.state映射和dispatch映射
import React from 'react'
import { connect } from 'react-redux' // 连接器
const App = (props) => {
return (
<>
<div>{props.num}</div>
</>
)
}
// 状态映射:将reducer中的state映射成props
// props.num去调用state的num
const mapStateProps = (state) => {
return {
num: state.num
}
}
// 事件派发映射:将reducer中的事件映射成props
// props.leijia()去实现num的累加
const mapDispatchToProps = (dispach) => {
return {
leijia() {
const action = {type:'a'} // 指定类型
dispach(action)
}
}
}
// export default connect(state映射,dispatch映射)(当前组件的名字)
export default connect(mapStateProps, mapDispatchToProps)(App)
// 创建初试状态
const defaultState = {
num: 1,
};
// eslint-disable-next-line import/no-anonymous-default-export
export default (state = defaultState, action) => {
// 这里需要深拷贝变量,不能修改原始数据
let newState = JSON.parse(JSON.stringify(state));
if (action.type === "a") {
newState.num++;
}
return newState;
};
18.路由安装和创建
npm i react-router-demo@6 --save
import ReactDOM from "react-dom";
import Router from "./router";
ReactDOM.render(
<Router />,
document.getElementById("root"),
);
import A from "../pages/A"; // 新建A组件
import B from "../pages/B"; // 新建B组件
import App from "../App"; // 引入承接页
import { BrowserRouter, Routes, Route } from "react-router-dom";
// BrowserRouter是history模式 不带# 需要配置nginx
// HashRouter是Hash模式 不带#
const BaseRouter = () => (
<BrowserRouter>
<Routes>
<Route path='/' element={<App />}>
<Route path='/A' element={<A />} />
<Route path='/B' element={<B />} />
<Route path='/C/:id' element={<C />} />
</Route>
</Routes>
</BrowserRouter>
)
export default BaseRouter
19.router的hooks
import React from 'react'
import { Outlet, Link, useLocation, useNavigate, useParams } from 'react-router-dom'
export default function App() {
const a = useLocation() // 获取页面路径信息
const navigate = useNavigate() // 页面跳转传参方法
const param = useParams() // 获取页面参数
console.log(111, a, param);
return (
<div>
<ul>
<li><Link to='/A'>首页</Link></li>
<li><Link to='/B'>测试</Link></li>
<li><Link to='/C'>测试区</Link></li>
</ul>
<button onClick={()=> navigate('/C', {state:{ id: 123 }})}>11s</button>
<hr />
<Outlet /> // 占位符 A、B、C组件展示在这里
</div>
)
}