一、那一刻
你有梦想吗,当然不要做梦都想!!!如果有那就继续吧!
不要对生活抱有幻想,因为不切实际!!!
宁要模糊的正确,也不要精确的错误!!!
在别人恐惧时贪婪,在别人贪婪时恐惧!!!
请控制好你的情绪,因为它可能跟随你一辈子,要么被它控制得体无完肤,要么将它诚服脚下!!!
那头山上山,这头路无边,走之行之!!!--林梦梵
二、react回溯链接
上一篇文章我们已经介绍了如何搭建nodejs环境以及react的基本使用是通过cdn的方式引入react框架的,如果还不了解react的可以看看基础篇;
java程序员的零基础react到运用的学习之路_林梦梵的博客-CSDN博客
三、react新篇章
简介:这里我们会介绍,react脚手架搭建项目,react的Hooks基本使用,redux状态管理、react-router路由使用、远程调用axios;
三.一、react脚手架搭建项目
在终端执行命令:npx create-react-app project_name
项目结构:
node_modules文件夹相当于java项目jar的maven库;
public文件夹我暂时不知道,index.html项目开始文件;
src文件夹就是我们主要写业务代码的文件夹了;
package.json文件相当于java的maven项目的pom文件;
启动项目:
启动命令:npm start
打开终端进入项目文件夹,执行命令:
看到如上图片说明启动成功,然后在浏览器访问地址:http://localhost:3000/
三.二、redux状态管理
场景化:
场景1:
如何在页面中更新数据和存储数据;
例如:如何在一个页面在输入的时候在这个页面的某处时时更新;
index.js代码:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import './App.css'
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
function App() {
return (
<div className="App">
输入文字:<input type='text' onChange={(a)=>{console.log('输入的内容:',a.target.value);}}/><br/>
<span>我是app,我也设置一个值:{}</span><br/>
</div>
);
}
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
浏览器展示:如何在写入的时候下面的值同步更新;
场景2:
在多个组件中如何传递参数以及如何管理数据,然后数据动态的在浏览器上更新又不会丢失呢;
例如:在组件Ba组件和App组件他们怎么传递参数并且时时更新数据;
Ba.js代码:
export default function Ba(){
return (<div>
<span>我是ba,我设置一个值:{}</span>
</div>);
}
App.js代码:
import './App.css';
import Ba from './Ba';
function App() {
return (
<div className="App">
输入文字:<input type='text' onChange={(a)=>{console.log('输入的内容:',a.target.value);}}/><button>更新</button><br/>
<span>我是app,我也设置一个值:{}</span><br/>
<Ba/>
</div>
);
}
export default App;
index.js代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
浏览器展示:如何在写入的时候下面的值同步更新;
状态管理redux组件的基本使用:
我们需要解决的问题,数据存储在哪里,怎么样更新页面的数据,怎么样其他的组件能够建立联系,那么使用一个观察者模式实现;简单说需要做:发布操作-》行为执行-》订阅接收变化;
安装组件:redux和react-redux,在项目的终端执行命令npm i redux react-redux
以上的代码修改之后变成:
场景化一代码更新为如下:
index.js代码:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import './App.css'
import reportWebVitals from './reportWebVitals';
import {legacy_createStore as createStore} from'redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
let initState={data:''};
function reduer(state=initState,action){
switch(action.type){
case 'change': state={data:action.param}; break;
// default:
}
return state;
}
let stroe = createStore(reduer);
function App() {
return (
<div className="App">
输入文字:<input type='text' onChange={(a)=>{console.log('输入的内容:',a.target.value);stroe.dispatch({type:'change',param:a.target.value})}}/><br/>
<span>我是app,我也设置一个值:{stroe.getState().data}</span><br/>
</div>
);
}
stroe.subscribe(()=>{
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
});
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
浏览器展示:
重点代码讲解:
-
createStore创建一个容器进行管理状态和行为,它需要传递一个函数,函数会接收状态和行为两个参数,返回得到一个管理对象;
-
以上提到的函数(reduer)它有两个参数,第一个参数就是状态对象也叫数据对象,第二个参数就是传递参数和行为的参数,该参数需要必须有一个属性为type,该属性就是用于识别需要做出什么反应的标识,同时还可以自定义属性用于传递和接收参数,例如我们用到的param属性;
-
订阅行为(stroe.subscribe),需要传递一个函数,就是当以上函数做出反应或者叫发布事件的时候去执行这个函数,当前就做更新虚拟dom行为;
-
发布行为(dispatch),需要传递一个对象,对象属性必须有一个type该数据就是告诉别人要做什么,其他的属性就是用于传递参数;
场景化二代码更新为如下:
index.js代码:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {legacy_createStore as createStore} from'redux';
import {Provider} from 'react-redux'
let initState={data:''};
function reduer(state=initState,action){
switch(action.type){
case 'change': state={data:action.param}; break;
// default:state;
}
return state;
}
let stroe = createStore(reduer);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={stroe}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
App.js代码:
import './App.css';
import Ba from './Ba';
import {connect} from 'react-redux';
function App(props) {
return (
<div className="App">
输入文字:<input type='text' onChange={(a)=>{console.log('输入的内容:',a.target.value);props.dispatch({type:'change',param:a.target.value});}}/><br/>
<span>我是app,我也设置一个值:{props.data}</span><br/>
<Ba/>
</div>
);
}
function back(state){
return state;
}
export default connect(back)(App);
Ba.js代码:
import {connect} from 'react-redux';
function Ba(props){
return (<div>
<span>我是ba,我设置一个值:{props.data}</span>
</div>);
}
function back(state){
return state;
}
export default connect(back)(Ba);
浏览器展示:
重点代码讲解:
-
createStore创建一个容器进行管理状态和行为,它需要传递一个函数,函数会接收状态和行为两个参数,返回得到一个管理对象;
-
以上提到的函数(reduer)它有两个参数,第一个参数就是状态对象也叫数据对象,第二个参数就是传递参数和行为的参数,该参数需要必须有一个属性为type,该属性就是用于识别需要做出什么反应的标识,同时还可以自定义属性用于传递和接收参数,例如我们用到的param属性;
-
将起始组件使用组件封装Provider(提供者),然后将store状态对象传递给它进行传递;
-
在需要获取状态数据的组件中添加connect组件进行注册订阅或者叫消费者,它需要传递一个函数获取状态对象,然后返回一个对象,对象将组件作为参数传递进去建立联系,同时暴露组件;
-
发布行为(dispatch),需要传递一个对象,对象属性必须有一个type该数据就是告诉别人要做什么,其他的属性就是用于传递参数;
三.三、react的Hooks基本使用介绍
react的官网地址:Hook 简介 | React中文网
hook的使用主要用于在function组件中;
useState:
是相当于class组件的的state,使用例如:const [count,setCount] = useState(0),定义一个变量count,同时需要设置一个一个以set开头后面跟变量一样的名字的变量,它是更新变量的方法,当执行set对应的方法时候对应用到了该变量的地方都会同时更新值;并且在useState上设置初始值;
注意:
- useState修饰的变量都是异步更新的;
- 执行set方法会同步更新count使用到的地方,相当于setState方法;
- 它相当于class组件的生命周期:componentDidMount和componentDidUpdate;
useEffect:
它的作用相当于class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API;同时它的写法有多种表达出来的功能也不一样;
写法多种:useEffect(step,dependencies),第二个参数不是必须的;
第一种写法,就是渲染组件完成后触发一次,并且每次组件更新的时候都会执行相当于class组件中生命周期函数:componentDidMount和componentDidUpdate;
useEffect(()=>{
console.log("");
});
第二种写法,就是渲染组件完成后触发,然后如果有依赖变量更新的时候也会更新,如果依赖组件为空数组,那么就只有在更新完成后执行一次;
//没有依赖组件只会执行一次
useEffect(()=>{
console.log("")
},[]);
//有依赖组件state,count,如果这两个变量值发生变化了那么就会执行第一个参数的函数
useEffect(()=>{
console.log("")
},[state,count]);
第三种写法,就是在组件被移除的时候执行,相当于class组件的生命周期的:componentWillUnmount和componentDidUpdate;
useEffect(()=>{
return ()=>{
console.log('');
}
});
useContext:
它就是相当于不在使用props进行父组件向子组件进行传递参数;它需要和createContext组件一起使用,该组件创建一个上下文对象,然后通过上下文对象进行设置为顶层组件,然后设置需要传递给子组件的变量,然后再需要接收创建的上下文对象的子组件中使用useContext进行接收返回的就是传递的参数,代码如下;
import React , { useState,useEffect,useContext,createContext } from 'react';
const TopContext = createContext(); //创建上下文对象
function New(){
const [count,setCount] = useState(()=>0);
useEffect(()=>{
console.log("执行")
});
useEffect(()=>{
console.log("我没有依赖组件")
},[]);
useEffect(()=>{
console.log("我有依赖组件")
},[count]);
useEffect(()=>{
return (()=>{
console.log("清理么")
})
})
return <div>
<TopContext.Provider value={{name:'yunming'}}>
<span>新闻</span><br/>
<span>{count}</span><br/>
<button onClick={()=>{setCount(count+1)}}>加1</button><br/>
<button onClick={()=>{setCount(count-1)}}>减1</button><br/>
<Child/>
</TopContext.Provider>
</div>
}
function Child(){
let data = useContext(TopContext);
return <div>
<span>{data.name}</span>
</div>
}
export default New;
useReducer:
它是useState的替换方案,它又相当于stroe里面的reducer,例子如下:
import React , { useReducer } from 'react';
let initState={count:0};
const reducer = function(state,action){
switch (action.type) {
case "add":
return {count:state.count+1}
break;
case "puls":
return {count:state.count-1}
break;
default:
return state;
break;
}
}
function New(){
const [countState,dispatch] = useReducer(reducer,initState);
return <div>
<span>新闻</span><br/>
<span>{countState.count}</span><br/>
<button onClick={()=>{dispatch({type:"add"})}}>加1</button><br/>
<button onClick={()=>{dispatch({type:"puls"})}}>减1</button><br/>
</div>
}
export default New;
useMemo:
它是为了优化性能的一个函数,它接收两个参数,第一个参数是函数,第二个参数是监听哪一个变量变更时触发函数执行,然后返回一个函数处理后的结果,它相当于useState+useEffect的集合;代码如下;
import React , { useReducer,useMemo } from 'react';
let initState={count:0};
const reducer = function(state,action){
switch (action.type) {
case "add":
return {count:state.count+1}
break;
case "puls":
return {count:state.count-1}
break;
default:
return state;
break;
}
}
function New(){
const [countState,dispatch] = useReducer(reducer,initState);
let date = useMemo(function(){
return countState.count+2;
},[countState]);
return <div>
<span>新闻</span><br/>
<span>{countState.count}</span><br/>
<span>memo的值:{date}</span><br/>
<button onClick={()=>{dispatch({type:"add"})}}>加1</button><br/>
<button onClick={()=>{dispatch({type:"puls"})}}>减1</button><br/>
</div>
}
export default New;
useRef:
它可以让我们可以获取组件中的DOM对象;
使用方式如下:它的方式相当于,先获取一个钩子对象放到哪一个dom元素上,在有dom行为的时候获取dom对象;
import React , { useState,useEffect,useContext,createContext,useReducer,useMemo,useRef } from 'react';
let initState={count:0};
const reducer = function(state,action){
switch (action.type) {
case "add":
return {count:state.count+1}
break;
case "puls":
return {count:state.count-1}
break;
default:
return state;
break;
}
}
function New(){
const [countState,dispatch] = useReducer(reducer,initState);
let domObj = useRef();
console.log("初始化ref:",domObj);
let date = useMemo(function(){
console.log("执行函数后获取ref:",domObj);
return countState.count+2;
},[countState]);
return <div>
<span>新闻</span><br/>
<span>{countState.count}</span><br/>
<span ref={domObj}>memo的值:{date}</span><br/>
<button onClick={()=>{dispatch({type:"add"})}}>加1</button><br/>
<button onClick={()=>{dispatch({type:"puls"})}}>减1</button><br/>
</div>
}
export default New;
memo:
memo函数,使用主要是保存组件状态,优化渲染性能的;如果主组件有渲染,子组件没有必要更新的则不更新,如果传递了函数或者参数的子组件也会重新渲染;
import React , { useState,useEffect,useContext,createContext,useReducer,useMemo,useRef,memo } from 'react';
let initState={count:0};
const reducer = function(state,action){
switch (action.type) {
case "add":
return {count:state.count+1}
break;
case "puls":
return {count:state.count-1}
break;
default:
return state;
break;
}
}
function New(){
const [countState,dispatch] = useReducer(reducer,initState);
let domObj = useRef();
console.log("初始化ref:",domObj);
let date = useMemo(function(){
console.log("执行函数后获取ref:",domObj);
return countState.count+2;
},[countState]);
return <div>
<span>新闻</span><br/>
<span>{countState.count}</span><br/>
<span ref={domObj}>memo的值:{date}</span><br/>
<button onClick={()=>{dispatch({type:"add"})}}>加1</button><br/>
<button onClick={()=>{dispatch({type:"puls"})}}>减1</button><br/>
<Lbb/>
</div>
}
let Lbb = memo(function Sdd(){
console.log("子组件渲染")
return <div>
<span>子组件</span>
</div>
})
export default New;
useCallback:
它的意思就是只要依赖项没有发生变化,那么它返回的对象传递个子组件的同时也不会触发值组件的重新渲染,如果依赖项发生了变化那么也就会跟着子组件重新渲染,如果没有设置依赖项那么就相当于没有使用useCallback一样;
import React , { useState,useReducer,useMemo,useRef,memo,useCallback } from 'react';
let initState={count:0};
const reducer = function(state,action){
switch (action.type) {
case "add":
return {count:state.count+1}
break;
case "puls":
return {count:state.count-1}
break;
default:
return state;
break;
}
}
function New(){
const [count,setCount] = useState(()=>0);
const [countState,dispatch] = useReducer(reducer,initState);
let domObj = useRef();
console.log("初始化ref:",domObj);
let date = useMemo(function(){
console.log("执行函数后获取ref:",domObj);
return countState.count+2;
},[countState]);
let bk = useCallback(date,[])
return <div>
<span>新闻</span><br/>
<span>{countState.count}</span><br/>
<span ref={domObj}>memo的值:{date}</span><br/>
<button onClick={()=>{dispatch({type:"add"})}}>加1</button><br/>
<button onClick={()=>{dispatch({type:"puls"})}}>减1</button><br/>
<Lbb data={bk}/>
</div>
}
let Lbb = memo(function Sdd(props){
console.log("子组件渲染")
return <div>
<span>子组件{props.data}</span>
</div>
})
export default New;
更多hook组件请到官网上查看;
三.四、axios远程调用框架使用介绍
安装axios:npm install axios
axios就是一个封装好的ajax工具组件,它可以设置拦截器做统一处理的事情;
使用方式例如:
import axios from "axios"
axios.get("http://127.0.0.1:8080/service").then((res)=>{
console.log(res);
});
注意:使用axios可能会遇到跨域问题;
解决跨域问题我这里说两种方式;
第一种方式,如果项目使用:webpack-dev-server组件,那么就在配置文件件中添加:devServer的属性porxy的对应参数;
devServer{
proxy:{
"/api":{
target:"http://127.0.0.1:8080",
changeOrigin:true,
pathRewrite:{"^/api":""}
}
}
}
第二种是使用http-porxy-middleware组件进行实现,使用方式请使用官方网站上的例子,需要在src目录下创建一个文件名为:setupProxy.js的文件,文件内容如下:
const { createHttpProxyMiddleware } = require("http-proxy-middleware")
modles.exports=function(app){
app.use("/api",createHttpProxyMiddleware({
target:"http://127.0.0.1:8080",
changeOrigin:true,
pathRewrite:{
"^/api":""
}
}))
}
上面使用到axios的代码修改后为:
import axios from "axios"
axios.get("/api/service").then((res)=>{
console.log(res);
})
axios有多种api,get请求、post请求、put请求等,请看官网api;Axios
三.五、react-router路由配置
按照组件:npm install react-router-dom
页面路由就是在浏览器上访问哪一个uri地址就显式什么菜单的内容:
代码如下:
App.js
import './App.css';
import Home from './Home';
import Heads from './Heads';
import { BrowserRouter as Router,Route,Routes } from 'react-router-dom';
function App() {
return (
<div className="App">
<h1>我是app</h1>
<Router>
<Routes>
<Route path='home' Component={Home}/>
<Route path='head' Component={Heads}/>
</Routes>
</Router>
</div>
);
}
export default App;
Home.js
export default function Home(){
return (<div>
<h1>我是home页面</h1>
</div>);
}
Heads.js
export default function Heads(){
return (<div>
<h1>我是head页面</h1>
</div>);
}
启动项目访问:http://localhost:3000/
访问:http://localhost:3000/home,访问结果如下:
访问:http://localhost:3000/head ,访问结果如下:
关键代码讲解:
路由设置是一个嵌套的:首先是Router-》Routes-》Route
其中Route的两个关键属性:path就是路由匹配设置,Component就是路由匹配之后显式哪一个组件的内容;在组件Router上有一个属性:basename如果设置值那么访问它里面的其他路由就需要拼接这个属性的值,例如设置为page,那么访问home就需要page/home才能访问了;
路由也可以进行统一管理和抽离在一个地方,高级用法下次见;
祝大家2023年中秋节快乐。做饭去了,后面的内容可能有些急促了,但是我想基本功能已经表达清楚了;