🔥 Umi官方文档地址
本篇文章主要介绍的一个 React小白
,从 0 使用umi
搭建React
项目的过程,记录了相关umi
的使用以及react
的相关知识点~
目录:
🌟持续更新中...🌟
1.在 config 文件内配置 title 无效问题;
2.favicon页面头部小图标配置无效;
3.className 样式选中高亮,或者多个 className 存在;
4.路由跳转和参数接受;
5.useState 和 useEffect;
6.如何用 dva 定义一个 Model,并修改;
7.权限路由(根据用户登录状态,跳转登录页);
8.组件通信;
9.函数式组件调用(forwardRef, useImperativeHandlede);
10.在React中显示html模块内容
11.修改List列表中的某一个数值
12.request请求配置
13.受控组件空值警告解决
14.useState()异步问题处理
15.打包后修改输出文件目录 outputPath
16.如何使用sass
17.createElement 和 cloneElement的区别
18.路由按需加载,Loading
19.部署后页面不显示问题
💎 1.在 config 文件内配置 title 无效问题
解决:如果你采用的是config方式,那就把默认的 .umirc.ts 文件删掉即可
💎 2.favicon页面头部小图标配置无效
解决:采用links引入,favicon适合引入对应链接的图标
💎 3.className 样式选中高亮,或者多个 className 存在
解决:
参考地址
className={`nav ${index === '1' ? 'active' : ''}`}
💎 4.路由跳转和参数接受
💎 5.useState 和 useEffect
Hook概览,建议仔细阅读文档
这里会牵扯到 useEffect 后面有无 [] 的解释
: 相当于 componentDidMount和componentDidUpdate,有点类似计算属性;
[] : 相当于 componentDidMount 执行一次,用来请求数据;
[值]: 相当于把方法与这个值绑定,值发生改变时,就会调用该方法;
export default function IndexPage(props) {
const [bannerList, setBannerList] = useState([])
const [count, setCount] = useState(0)
useEffect(() => {
getBannerList().then(res=>{
//储存轮播图数据
setBannerList(res.data)
})
}, [])
useEffect(()=>{
//这里每次点击add按键就会返回
console.log(count);
})
return (
<>
<div className='top'>
<Banner list={bannerList} />
<h1 className='title'>寄内地</h1>
<button onClick={() => setCount(count + 1)}>add</button>
</div>
</>
);
}
💎 6.如何用 dva 定义一个 Model,并修改
总而言之,这家伙有点类似于
vuex
,相当于用来处理全局数据的一个东西,希望下面的几个文章可以帮到你
例子:
这是我简单写的一个切换用户名的Model案例
需要留意的地方我已经用 红色 标记出来了,尤其是 { } ,如果没有的话,默认会接受一个 props ,在路由页面传参中有提到
💎 7.权限路由(根据用户登录状态,跳转登录页)
约定式路由,如果按照官方推荐的目录结构,是可以不用配置路由表的,它会自动生成
这里有两种写法,一种是放在route
路由表里,另一种是直接在指定页面写,看个人需求。
写法1:wrappers
写法2:权限路由 👍
💎 8.组件通信
👍 React 中组件间通信的几种方式
子用父:将数据绑定到子组件上,子组件通过props接收;
//父组件
<Fu value={值} />
...
//子组件调用
this.props.value
父用子:通过useRef()
定义,并在子组件上绑定ref,.current
获取DOM;
//父组件
const ziRef = useRef(null)
<Zi ref={ziRef} />
ziRef.current.state.{值}
子改父:通过在子组件上绑定一个关联父组件的方法数据
//父组件
<Fu onChange={(值)=>{改值方法}} />
...
//子组件调用
this.props.onChange(值)
父改子:通过useRef()
定义,并在子组件上绑定ref,.current
调用子组件定义修改值的方法;
//父组件
const ziRef = useRef(null)
<Zi ref={ziRef} />
ziRef.current.onChange(值)
...
//子组件
onChange = (值)=>{
改值方法
}
💎 9.函数式组件调用(forwardRef, useImperativeHandlede)
报错信息:
**Warning:**devScripts.js:6523 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
如果你在封装的组件上使用ref,那你就会发现这个错误,这就属于函数式调用,需要 useRef forwardRef
的使用,同时还能配合 useImperativeHandlede
来暴露子组件的数值或者方法给父组件使用。
👍 React函数式组件值之useRef()和useImperativeHandle()
👍 React Hooks系列之useImperativeHandle
💎 10.在React中显示html模块内容
<div dangerouslySetInnerHTML={{ __html: '版权 ©' }} />
💎11.修改List列表中的某一个数值
const [list,handleList] = useState([])
...
{
list.map((val, index) =><span onClick={() => {
let arr = [...list]
arr[index] = '修改'
handleList(arr)
}}>点击修改list{index}的数值</span>
)}
💎12.request请求配置
umi-request配置说明
本地端口号修改
如何获取后端的相应数据 data
src/utils/request.js
/** Request 网络请求工具 更详细的 api 文档: https://github.com/umijs/umi-request */
import { extend } from 'umi-request';
import { Toast } from 'antd-mobile';
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
};
/** 异常处理程序 */
const errorHandler = (error) => {
const { response } = error;
console.log(response);
if (response && response.status) {
const errorText = codeMessage[response.status] || response.statusText;
const { status, url } = response;
Toast.info({
message: `请求错误 ${status}: ${url}`,
description: errorText,
});
} else if (!response) {
Toast.info({
description: '您的网络发生异常,无法连接服务器',
message: '网络异常',
});
}
return response;
};
/** 配置request请求时的默认参数 */
const request = extend({
// prefix: 'http://192.168.0.115', //配置域名
timeout: 3000, //请求超时时间
headers: {},
// errorHandler,
// 默认错误处理
credentials: 'include', // 默认请求是否带上cookie
});
// 请求拦截
request.interceptors.request.use((url, options) => {
options.headers['Authorization'] = 'Bearer'
return {
url,
options: { ...options, interceptors: true },
};
});
// 响应拦截
request.interceptors.response.use(async (response) => {
const data = await response.clone().json();
if (data.code !== 200) {
Toast.info(data.message)
}
return response;
});
export default request;
使用
import request from '@/utils/request';
export function loginIn(data) {
return request('/api/login/account', {
method: 'POST',
data,
});
}
💎 13.受控组件空值警告解决
解决方法
//defaultValue 替换 `input` 上的 value
<input name='mobile' placeholder='电话' defaultValue={msg.mobile} onChange={handleInput} type="text" />
//or
<input name='mobile' placeholder='电话' value={msg.mobile || ''} onChange={handleInput} type="text" />
💎 14.useState()异步问题处理
下面的预期在某些时候并不是你想要的
const [num,handleNum] = useState(0)
...
useEffect(() => {
handleNum(1)
console.log(num) //0
handleNum(2)
console.log(num) //0
}, []);
例如:在移动端滑动加载更多 list,根据搜索条件去更新 list,每次条件的变化就需要重新让 list = [],然后再去获取新的 list,此时就会遇到这种 list 不能及时更新清空的问题
const [search,handleSearch] = useState('')
const [list,setList] = useState([])
获取list数据
const fetchList = ()=> {
getList().then(res=>{
setList(...list,...res.data)
})
}
//根据筛选条件加载数据
useEffect(() => {
setList([]) //设想每次变化时就清空 list
fetchList() //但是在处理数据并没有及时清空 list
}, [search]);
解决:
...
//每次条件变化就会清空 list
useEffect(() => {
setList([])
}, [search]);
//list发生变化就去调用接口数据
useEffect(() => {
//判断当list为[]时,调用接口
if(!list.length){
fetchList()
}
}, [list]);
💎 15.打包后修改输出文件目录 outputPath
outputPath 配置
outputPath:dist/shunfeng
,打包后会生成 dist
文件下shunfeng
文件下的其他文件
💎 16.如何使用sass
umi中使用sass只需安装 @umijs/plugin-sass
yarn add @umijs/plugin-sass --D
安装完后无需配置,umi会自己识别。默认使用dart sass , 如果需要使用node-sass,才需要想官网那样 配置
💎 17.createElement 和 cloneElement的区别
区别:传入的第一个参数不同
React.createElement()
它接受三个参数,第一个参数可以是一个标签名。如 div、span,或者 React 组件。第二个参数为传入的属性。第三个以及之后的参数,皆作为组件的子组件。
React.createElement(type, [props], [...children]);
React.cloneElement()
React.cloneElement()
与 React.createElement()
相似,不同的是它传入的第一个参数是一个 React 元素,而不是标签名或组件。新添加的属性会并入原有的属性,传入到返回的新元素中,而旧的子元素将被替换。将保留原始元素的键和引用。
React.cloneElement(element, [props], [...children]);
💎 18.路由按需加载,Loading
export default {
dynamicImport: {
loading: '@/Loading', //Loading组件
},
};
💎 19.部署后页面不显示问题
// 生产 测试配置
base: process.env.NODE_ENV === 'production' ? '/foo/' : '/',
publicPath: process.env.NODE_ENV === 'production' ? '/foo/' : '/',