Create React App 是用 React 创建新的单页应用的最佳方式。
单页面应用(single-page application),是一个应用程序,它可以加载单个 HTML 页面,以及运行应用程序所需的所有必要资源(例如 JavaScript 和 CSS)。与页面或后续页面的任何交互,都不再需要往返 server 加载资源,即页面不会重新加载。你可以使用 React 来构建单页应用程序,但不是必须如此。React 还可用于增强现有网站的小部分,使其增加额外交互。用 React 编写的代码,可以与服务器端渲染的标记(例如 PHP)或其他客户端库和平共处。
参考:https://react.docschina.org/docs/create-a-new-react-app.html#create-react-app
1、路由
参考:https://create-react-app.dev/docs/adding-a-router
https://reacttraining.com/react-router/web/guides/quick-start
2、环境变量
参考:https://create-react-app.dev/docs/adding-custom-environment-variables
示例如下:
.env.development文件
REACT_APP_BASE_API = /v1
3、开发版请求代理
参考:https://create-react-app.dev/docs/proxying-api-requests-in-development
https://segmentfault.com/q/1010000016754248/
如果proxy的值是字符串,可以在package.json里添加proxy字段,例如:
"proxy": "http://localhost:4000"
如果proxy的值是一个json,则需要做如下修改:cnpm i http-proxy-middleware --save-dev;src文件夹根目录下创建 setupProxy.js 文件编辑proxy代码,例如
const proxy = require(‘http-proxy-middleware‘); module.exports = function(app) { app.use([process.env.REACT_APP_BASE_API], proxy({ target: ‘http://localhost:5000‘, changeOrigin: true })); };
4、react-app-rewired
参考:https://github.com/timarney/react-app-rewired/blob/master/README_zh.md
https://github.com/arackaf/customize-cra
此工具可以在不 ‘eject‘ 也不创建额外 react-scripts 的情况下修改 create-react-app 内置的 webpack 配置,然后你将拥有 create-react-app 的一切特性,且可以根据你的需要去配置 webpack 的 plugins, loaders 等。
customize-cra提供了一组用于自定义利用react-app-rewired核心功能的Create React App v2配置,可以通过config-overrides.js文件来对webpack配置进行扩展。
4.1)自定义webpack配置如resolve.alias【创建
import
或 require
的别名,来确保模块引入变得更简单】
// config-overrides.js const { override, addWebpackAlias } = require(‘customize-cra‘); const path = require(‘path‘); module.exports = override( // 配置路径别名 addWebpackAlias({ pages: path.resolve(__dirname, ‘src/pages‘), utils: path.resolve(__dirname, ‘src/utils‘), assets: path.resolve(__dirname, ‘src/assets‘) }) )
4.2)使用 antd-mobile 进行web开发【antd-mobile
是 Ant Design 的移动规范的 React 实现;antd
是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品】
参考:https://mobile.ant.design/docs/react/use-with-create-react-app-cn
安装:npm install antd-mobile --save
按需加载:使用 babel-plugin-import【用于按需加载组件代码和样式的 babel 插件】
按需加载原理参考:https://ant.design/docs/react/getting-started-cn#按需加载
// config-overrides.js const { override, fixBabelImports } = require(‘customize-cra‘); const path = require(‘path‘); module.exports = override( fixBabelImports(‘import‘, { libraryName: ‘antd-mobile‘, style: ‘css‘ }) )
然后只需从 antd-mobile 引入模块即可,无需单独引入样式,babel-plugin-import 会帮助你加载 JS 和 CSS
其它问题
1)postcss autoprefixer不生效
解决方法:修改package.json的browserslist属性
// 修改前 "browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } // 修改后 "browserslist": { "development": [ "> 1%", "last 2 versions" ] }
2)样式冲突
参考: https://create-react-app.dev/docs/adding-a-css-modules-stylesheet
css模块化文件命名规则为[name].module.css 或 [name].module.scss
或 [name].module.sass,它
允许你在不同的文件中使用相同的css类名而不用担心命名冲突【会自动生成唯一的类名,格式为[filename]_[classname]__[hash]】
import React, { Component } from ‘react‘; import styles from ‘./style.module.scss‘; class PrdDetail extends Component { render() { return ( <div className={styles["detail-container"]}> <div className={styles.left}></div> </div> ); } }
浏览器渲染:
个人感觉使用起来很麻烦,特别是存在公共样式时
react
- JSX,是一个 JavaScript 的语法扩展。
我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。
在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase
(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。例如,JSX 里的 class
变成了 className
,而 tabindex
则变为 tabIndex
。
React 只更新它需要更新的部分:React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。
为了便于阅读,我们会将 JSX 拆分为多行。同时,我们建议将内容包裹在括号中,虽然这样做不是强制要求的,但是这可以避免遇到自动插入分号陷阱。
- 受控组件
在 HTML 中,表单元素(如<input>
、 <textarea>
和 <select>
)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态通常保存在组件的 state 属性中,并且只能通过使用 setState()
来更新。对于受控组件来说,每个 state 突变都有一个相关的处理函数。
class Login extends Component { constructor(props) { super(props); this.state = { codeBtnText: ‘获取验证码‘, phone: ‘‘ } } phoneChange(e) { this.setState({ phone: e.target.value }) } sendPhoneCode() { console.log(this.state.phone) } render() { return ( <div className="login-box"> <div className="input-row"> <input type="tel" className="phone-input" maxLength="11" placeholder="请输入手机号" value={this.state.phone} onChange={this.phoneChange.bind(this)} /> </div> <div className="input-row code-row"> <input type="text" className="code-input" maxLength="6" placeholder="请输入短信验证码" value={this.state.phoneCode} /> <input type="button" className="code-btn" value={this.state.codeBtnText} onClick={this.sendPhoneCode.bind(this)} /> </div> </div> ); } }
- 列表&key
参考:https://react.docschina.org/docs/lists-and-keys.html
https://es6.ruanyifeng.com/#docs/class#实例属性的新写法
使用 Javascript 中的 map()
方法来遍历 numbers
数组。【类的实例属性除了定义在constructor()
方法里面的this
上面,也可以定义在类的最顶层。】
class Index extends Component { state = {navs: []} componentDidMount() { request({ url: ‘group/groupContentList/zysrf_index_nav‘ }).then(response => { this.setState({navs: response.data}) }) } render() { const imgPrefix = process.env.REACT_APP_IMG_PREFIX return ( <div className="index-container"> <div className="nav-box clearfix"> {this.state.navs.map(nav => ( <div className="nav-item" key={nav.id}> <img src={imgPrefix nav.img_url} /> <p>{nav.title}</p> </div> ))} </div> </div> ); } }
key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据 id 来作为元素的 key。当元素没有确定 id 的时候,万不得已你可以使用元素索引 index 作为 key。如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值。
-
组合
参考:https://react.docschina.org/docs/composition-vs-inheritance.html
有些组件无法提前知晓它们子组件的具体内容。在 Sidebar
(侧边栏)和 Dialog
(对话框)等展现通用容器(box)的组件中特别容易遇到这种情况。我们建议这些组件使用一个特殊的 children
prop 来将他们的子组件传递到渲染结果中。
- 条件渲染
React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if
或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。你可以使用变量来储存元素,它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变。
JSX 中内联条件渲染的方法:
1)与运算符 &&
通过花括号包裹代码,你可以在 JSX 中嵌入任何表达式。这也包括 JavaScript 中的逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染。
function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); } const messages = [‘React‘, ‘Re: React‘, ‘Re:Re: React‘]; ReactDOM.render( <Mailbox unreadMessages={messages} />, document.getElementById(‘root‘) );
在 JavaScript 中,true && expression
总是会返回 expression
, 而 false && expression
总是会返回 false
。因此,如果条件是 true
,&&
右侧的元素就会被渲染,如果是 false
,React 会忽略并跳过它。
2)三目运算符
另一种内联条件渲染的方法是使用 JavaScript 中的三目运算符 condition ? true : false
。
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> The user is <b>{isLoggedIn ? ‘currently‘ : ‘not‘}</b> logged in. </div> ); }
- 组件 & Props & State
// 函数组件 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } // class组件 class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } // 渲染组件 const element = <Welcome name="Sara" />; ReactDOM.render( element, document.getElementById(‘root‘) );
Props 的只读性:组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。
应用程序的 UI 是动态的,并会伴随着时间的推移而变化。在不违反props规则的情况下,state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容。
react-router4
- 路由传参
参考:https://reacttraining.com/react-router/web/api/Route/route-props
import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter as Router, Route } from "react-router-dom"; // All route props (match, location and history) are available to User function User(props) { return <h1>Hello {props.match.params.username}!</h1>; } ReactDOM.render( <Router> <Route path="/user/:username" component={User} /> </Router>, node );