本篇文章并不是按照官网API由易到难讲解,而是按照我所做的项目实践得出的结论。可能有些写的并不是绝对的完美的方案,我们可以一起讨论,并且我也是在学习当中。可能有自己遇到的一些坑的一些解决方案,希望能在工作中帮助到大家😄。
React基本概念还是需要看下官网API,了解并熟知React的语法概念和组件化思想,生命周期要熟悉。ES6常用特性要熟悉。
看身边的同事,意识到不一定是前端可以学会React,如果你会其他语言,同样也能入门。
关于React脚手架 create-react-app 安装配置我在另一篇幅有讲:https://www.jianshu.com/p/b168c47a7620
React是什么?
React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库。使用React可以将一些简短、独立的代码片段组合成复杂的UI界面,这些代码片段被称作“组件”。
class HelloWorld extends Component {
//初始化组件状态
constructor(props) {
super(props)
this.state = {
loading: false
}
}
componentDidMount(){
//调用API
}
render() {
return <div>hello world!</div>
}
}
export default HelloWorld
由此看出以上是一个简单的组件,this.state是对状态的一个初始化赋值的概念。它是一个有状态的组件,具有完整的生命周期概念。但项目中不仅仅是只用这种有状态组件,还有其他组件类型。
而无状态组件是通过无状态的函数创建的,它是一种只负责展示的纯组件。无状态组件的特点是不需要管理组件状态state,数据直接通过props传入即可,这也符合React单向数据流的思想。
这里可以科普下无状态组件的概念:
无状态组件
无状态组件可以通过减少继承Component而来的生命周期函数而达到性能优化的效果。从本质上来说,无状态组件就是一个单纯的render函数,所以无状态组件的缺点也是显而易见的。因为它没有shouldComponentUpdate生命周期函数,所以每次state更新,它都会重新绘制render函数。
对于无状态组件的函数式生命方法,不仅可以提高代码的可阅读行,还能大大的减少代码量,提高代码的复用率。
以下是我项目中所写的无状态组件。
const ScaleScorePage = (props) => {
const patientScales = props.patientStatus.get('newScales')
return (
<div className={styles.commonDiagnosisWrapper}>
<div className={styles.commonDiagnosisTitle}>
<h3>卒中严重程度评估</h3>
</div>
{patientScales &&
<div className={styles.commonDiagnosisInner}>
<Row>
{renderBaseScoreInner(patientScales)}
</Row>
</div>
}
<div className={styles["text-right"]} style={{display: 'none'}}><Button>查看出院时量表评分</Button></div>
</div>
)
}
export default ScaleScorePage
以上代码中props是父组件传递过来的属性。此时就用到了父组件如何向子组件通信,父组件通过props给子组件传递数据。如下示例:
<ScaleScorePage patientStatus={patientStatus}/>
上面的patientStatus就是属性值通过props传递给子组件ScaleScorePage。
思考:如何在这种无状态组件中想用到生命周期的概念呢?这个就要用到React 16.8的新增特性Hook,它可以让你在不编写class的情况下使用state以及其他的React特性。
Hook
最近项目中用到的示例:
主要用到的就是 useState ,以及 useEffect
import React, { useEffect, useState } from "react"
import {Button} from 'antd';
import {connect} from "react-redux";
import styles from '../../css/diagnosis/diagnosis.module.css'
import {getPatientComplaint} from "../../actions";
const PatientStatement = (props) => {
const {patientID,patientComplaint} = props
const [basePatientDetails, onPatientStatementChange] = useState(false)
useEffect(() =>{props.getPatientComplaint(patientID)},[])
return (
<div className={styles.commonDiagnosisWrapper}>
<div className={`${styles.commonDiagnosisTitle} ${styles.commonDiagnosisTitle1}`}>
<h3>主诉</h3>
<Button style={{display: 'none'}} type="primary" key="ignore" onClick={()=>onPatientStatementChange(!basePatientDetails)}>
{basePatientDetails ? '保存' : '编辑'}
</Button>
<span style={{float: 'right'}}>记录时间: 暂无</span>
</div>
<ul>
{patientComplaint.map((item,idx)=><li key={item.id}>{item}</li>)}
</ul>
</div>
)
}
const mapStateToProps = state => {
return {
patientComplaint: state.diagnosis.get('patientComplaint')
}
}
export default connect(mapStateToProps,{getPatientComplaint})(PatientStatement)
由以上get的知识点的涵盖面可能有点多,首先可以忽略redux这部分内容,这个可以单独几个篇幅去讲解。如何从父组件向子组件传递值上面已经讲过,下面就是讲解useState.
useState
// 声明一个叫做basePatientDetails的 state 变量,
const [basePatientDetails, onPatientStatementChange] = useState(false)
声明一个叫做basePatientDetails的 state 变量,初始化值设置为false,并且在onPatientStatementChange方法中改变state变量的值。
useEffect
Effect Hook 可以让你在函数组件中执行副作用操作。如果你熟悉React class的生命周期,你可以把useEffect 看作是componentDidMount , componentDidUpdate和componentWillUnmount这三个函数的组合。
useEffect(() ={ props.getPatientComplaint(patientID) } ) //xxxx
useEffect(() ={ props.getPatientComplaint(patientID) },[] )
⚠️注意:以上写法是有个箭头函数,然后执行了一个API接口调用。因为它具有生命周期的概念,这样又陷入万恶的循环中,所以解决办法是在结尾加 [].
css样式模块化
另外在样式上,最开始写项目的时候,发现引用的css样式是全局的样式,会经常出现样式覆盖问题。这样对于团队开发是非常不友好的。后来在项目中对css起的名字做了研究,xxx.module.css这样自动对css样式进行模块化管理。只需要在组件引用的时候使用
//如果引用多个样式文件
import styles from '../../css/diagnosis/diagnosis.module.css'
import iStyles from '../../css/infomation.module.css'
使用时候这样用,以下有单个类名以及多个类名示例:
<div className={styles.outer}>
<div className={`${styles.inner} ${iStyles.border}`}>
</div>
解构赋值
const { patientID,patientComplaint } = props
//等价于
const patientID = props.patientID
const patientComplaint = props.patientComplaint
列表 & key
map方法非常实用。
<ul>
{patientComplaint.map((item,idx)=><li key={item.id}>{item}</li>)}
</ul>
由此map方法使用前提必须是一个数组,参数( currentValue, index, arr )。
currentValue (必须。当前元素的值)
index (可选。当前元素的索引值)
arr (可选。当前元素属于的数组对象)
另外:还会有数据改造的情况(出现于后台字段跟前端所用字段不一致)
const renderExamTitle = (item) => {
return <Fragment><span>{item.examItem||''}</span><span style={{float: 'right'}}>{item.examUnit||''}</span></Fragment>
}
const renderExamResult = (item, params, style1) => {
return <Fragment><span style={style1}>{item.examResult?item.examResult:'无'} {params}</span></Fragment>
}
/**处理数值变化值*/
const handlerExamResult = (item) => {
switch (item.examStatus) {
case 'u':
return renderExamResult(item, '↑', {color: '#d90f0f'})
case 'd':
return renderExamResult(item, '↓', {color: '#d90f0f'})
default:
return renderExamResult(item, '');
}
}
const handlerBody = (data) => {
// 接口数据映射处理
return data.map((item, index) =>({
key: index,
examItem: renderExamTitle(item),
examResult: handlerExamResult(item),
maleStd: item.maleStd
}))
}
思考💡:
假设如果后台给的数据是长得这个样子,需要前端页面进行循环处理结构。
const options = {
"正常或近乎正常": "0-1分",
"轻度卒中/小卒中": "2-4分",
"中度卒中": "5-15分",
"中-重度卒中": "16-20分",
"重度卒中": "21-42分"}
提示💡:
console.log( Object.keys(options) )
//expected output: ["正常或近乎正常", "轻度卒中/小卒中", "中度卒中", "中-重度卒中", "重度卒中"]
console.log( Object.values(options) )
//exoected output: ["0-1分", "2-4分", "5-15分", "16-20分", "21-42分"]
由此你是不是有思路了。get it 😄!
<ul className={styles.scaleScoreText}>
{Object.keys(options).map((itm, idx) => <li key={idx}>{options[itm]}<p>{itm}</p></li>)}
</ul>
React 中的三元运算符
如果在jsx语句中用到if-else 语句进行条件渲染怎么办?可以使用三元运算符:
{
nodeDetails.isFinal?
<div>有数据 </div> : <div>暂无结果</div>
}
<div>参考范围 {item.range=== null?'暂无':item.range}</div>
如果只返回条件渲染的一方面,可以使用&&运算符
{
data.checks.length>0 &&<div>显示....</div>
}
补充:
1.let arr = ['a','b','c'] 改造成===> obj = {a:1,b:1,c:1}
let arr = ['a','b','c']
let obj = {}
arr.map(item=>obj[item] = 1)
console.log(obj)
未完待续。。。
网友评论