React 从诞生之初就是可被逐步采用的,因而你可以按需引入或多或少的 React 特性。不管你是想体验下 React,用它给简单的 HTML 页面增加一点交互,还是要开始一个完全由 React 驱动的复杂应用,该章节内容里的链接都能帮你快速开始。
如果你对体验 React 感兴趣,可以尝试在线代码编辑器。从 CodePen,CodeSandbox,Glitch, 或者 Stackblitz 开始一个 React 版本的 Hello World 模版。
如果你喜欢使用自己的文本编辑器,也可以下载这个 HTML 文件,然后编辑文件内容,最后再用浏览器从本地文件系统打开文件,预览页面效果。注意:这个文件中包含一个低效率的运行时代码转换脚本,所以我们推荐仅在简单的演示项目中使用。
你可以立即在 HTML 文件中添加 React,然后选择逐渐拓展它的应用范围,或只在一些动态小部件中使用它。
当你刚开始一个 React 应用时,通过 HTML 的 script 标签引入 React 依然是最好的选项,因为这能让你的项目立即启动。
但随着应用越来越大,你可能会需要更加集成化的安装方式。我们推荐了一些 JavaScript 工具链,它们适合大型应用。它们只需很少甚至零配置,就能让你充分利用丰富的 React 生态。立即尝试。
官方提示: React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。
使用js表达式需要加括号{}
: 表达式是一个值
const name = 'Josh Perez';
const element = Hello, {name}
;
ReactDOM.render(
element,
document.getElementById('root')
);
//等效的两种写法
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
const element = (
Hello, world!
);
//React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
属性使用
内联样式使用style={{key:value}}形式,如果原生css属性中有-,则属性第二个字符大写如font-size需要改为fontSize
//class <-> className
//style=“color:red;front-size:20px” <-> style={{color:‘red’ fontSize:‘20px’}}
3. jsx中渲染: 最外层只有一个根标签
```react
const element = (
Hello!
Good to see you here.
);
标签
//标签必须关闭否则报错
//不要使用自定义标签,除非你想使用组件,且组件名首字母需要大写
//react识别标签如果是小写字母开头则将其转为html标签如果没有与之对应的标签则报错
//首字母大写则是组件,如果没有该组件则报错
循环
const element = (
{
//item中需要有id属性赋予key唯一值
data.map(item,index)=>{
return - {item}
}
}
);
官方调试工具: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
//安装react插件React-Native/React/Redux snippets for es6/es7 代码片段 在vscode里快捷创建函数组件输入 rfc回车
function Demo () {
this;//babel编译会开启严格模式this指向undefined,在js中指向的是Window
return demo
}
ReactDOM.render( ,document.getElementById('demo'))
//代码片段 在vscode里快捷创建类式组件 rcc回车
//必须继承react内置类 类名大写
class Person extends React.Component{
name
age
//需要初始化
constructor(name,age){
//this指向实例对象
this.name = name
this.age=age
}
render(){
//必须有render方法,且必须有返回值
return honshen
}
}
//调用了new Person得到实例对象,且调用render方法,方法中的this指向其实例对象
ReactDOM.render( ,document.getElementById('demo'))
constructor (prpos){
this.state = {} //初始化state
this.setState() //更新状态
this.state.name //读取name
}
class B extends Components{
//读取属性
this.props
}
//ref类似于getElementById
class B extends Components{
func = () => {
const {scanIn} = this.refs
scanIn.value //输入框的值
this.input.value //获取输入的值
}
render(
{this.input = input}} /> //推荐
)
}
//不使用柯里化函数
function func(event,data) {
//函数体
}
{this.func(event,data)}}
//柯里化函数
function func (data){
return (event)=>{
//函数体
}
}
//全局安装
npm i -g create-react-app
//创建应用
create-react-app my-app
webpack配置文件都已隐藏通过: yaen eject暴露webpack.config.js
//建议使用axios请求库
//使用json-server配合调试 axios github地址: https://github.com/typicode/json-server
npm i -g json-server
//在项目文件夹下创建db.json
//在db.json目录监视监视json
json-server --watch db.json
//axios github地址: https://github.com/axios/axios
npm i axios --save
//get请求
axios({
//请求类型 GET POST PUT DELETE
method: "GET",
//请求地址
url: ""
//请求体
data:{
}
}).then((res)=>{
//回调
})
//方法1: 在package.json中配置
"proxy": "http://localhost:5000"
//方法二: 新建setupProxy.js文件
const proxy = require('http-proxy-middleware');
module.exports = function(app){
app.use(
proxy('请求路径',{
target: '目标地址',
changeOrigin: true, //修改请求源host
pathRewrite: {'^请求路径':''}
})
),
proxy('请求路径',{
target: '目标地址',
changeOrigin: true, //修改请求源host
pathRewrite: {'^请求路径':''}
})
)
}
//父组件直接传递数据给子组件
//子组件接收数据
const {data} = this.props
//子组件将state提升到父组件里
//子组件修改父组件的数据
change(){}
订阅消息:
1. 消息名
2. 消息发布
//使用库 PubSubJs
npm i pubsub-js --save
//在componentDidMount(){}中订阅消息
PubSub.subscribe('消息名',(_,data)=>{
//处理
})
集中管理组件中多个共享的状态
谷歌浏览器插件: redux-dev-tools
npm i redux-devtools-extension --save
//修改store.js
import {composeWithDevTools} from 'redux-devtools-extension'
import {createStore,combineReducers,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
const allReducer = combineReducers({
//对象
})
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KX7REb6I-1619771333081)(https://images-1300732204.cos.ap-chengdu.myqcloud.com/MarkDown/Snipaste_2021-04-01_21-04-56.png.png)]
三个原则:
1.单一数据源
2.State 是只读的
3.使用纯函数来执行修改
// 1.如何得到此对象?
import {createStore} from 'redux";
import reducer from './reducers'
const store = createStore(reducer)
// 2.此对象的功能?”
getState() //得到state
dispatch(action) // 分发action,触发reducer调用,产生新的 state
subscribe(listener) //注册监听,当产生了新的state时,自动调用
redux使用引用类型进行的是浅比较例如数组返回不能这样reture arr.unshift(data)
这样返回的是arr的地址和原来的值一样redux不会更新状态,可以使用return [data,...arr]
redux必须使用纯函数:同一个输入只有同一个输出
适用于组组件与后代组件通信
//在组组件中创建上下文对象Con是一个容器对象
const Con = React.createContext()
const {Provider} = Con
const {Consumer} = Con
//子组件被上下文包裹
//在son的内部组价都能收到data但必须声明使用,通过后代组件的this.context
//在son组件内部想要使用context的组件需要声明使用=类式组件
static contextType = Con
this.context; //获取context对象
//也可以使用这样的方式在需要使用数据的地方--函数组件
{
value => {
//函数
//返回一个组件
}
}
SPA: 单页面应用,点击页面不会刷新只会做局部更新
import 'react-router-dom';
//默认是push,点击后向栈顶加入,当使用 时不能回退历史记录
{//注册路由,模糊匹配}
{//严格匹配,不能随便开}
{//路由组件会默认收到一些props, this.props查看一下
//如果多个路由的path一致则同时展示两个组件,但这种不好,建议合并两个为一个组件
//路由较多时使用
/*react样式丢失问题: 当在多级路由路径下刷新时,index.html中引入的css样式会请求相应css但路由所在路径刷新导致请求失败react会返回index.html的内容所以css请求返回的是index.html
解决方法: 1. 引入css使用根路径
2. 使用%PUBLIC_URL%作为样式的路径,推荐
3. 使用HashRouter
*/}
//当模糊匹配失败时
//例如请求 /home/me 先匹配/home 当/home/me是Home组件
//组件1中
//匹配成功
//写在所有路由的最下方
//app中
//匹配成功
//写在所有路由的最下方
//1. 路径传参params 路由占位符 :
//传参
//在注册路由时声明接收参数this.props.match.params中能够拿到id和info
//2. 传递search参数
//传参
//无需申明接收参数,this.props.location.search中得到?id=12&info=12需要对search参数编码
//需要引入库 querystring
import qs from 'querystring'
qs.stringify(obj); //将对象转换为字符串
qs.parse(str); //将字符串转换为对象 qs.parse(this.props.location.search.slice(1))去除?号
//3. 传递state参数,这里的state不是组件的state,而是路由的参数,前两种参数传递会在地址栏显示但state传参不会
//无需申明接收参数在组件的this.props.location.state中,此种情况下state的参数由BrowserRouter维护,刷新页面不会丢失值,当清空浏览器的历史记录时会丢失
//路由组件中的导航函数
replace () {
this.props.history.replace('/idnex') //不能返回
//携带state参数
this.props.history.replace('/index',{id: 2,title: 1})
//前进
this.props.history.goForward(); //前进
this.props.history.goBack(); //后退
}
push (){
this.props.history.push('/idnex') //可返回
}
//一般组件导航
import {withRouter} from 'react-router-dom
class Header extends Component {
}
export default withRouter(Header) //withRouter是一个函数返回值是一个新组件,加工了Header组件使之可以使用路由组件的一些函数
1.底层原理
BrowserRouter使用的是H5的history API不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。
2.ur1表现形式不一样
BrowserRouter的路径中没有#
例如: localhost: 3000/demo/testHashRouter的路径包含#,例如: localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失。
4.备注: HashRouter可以用于解决一些路径错误相关的问题。
//按钮
import 'antd/dist/antd.css';
import { Button } from 'antd';
} /> //引入图标
//图标
import 'antd/dist/antd.css';
import {
HomeOutlined,
SettingFilled,
SmileOutlined,
SyncOutlined,
LoadingOutlined,
} from '@ant-design/icons';
//样式按需引入
官网中: https://ant.design/docs/react/use-with-create-react-app-cn
建议3.x版本: https://3x.ant.design/docs/react/use-with-create-react-app-cn
https://3x.ant.design/docs/react/use-with-create-react-app-cn
https://3x.ant.design/docs/react/customize-theme-cn
npm run build
# 使用第三方库快速搭建服务 seve会以当前文件夹作为服务器根目录
npm i serve -g #-g要写在最后
serve # 启动服务器
serve demo # 以当前文件夹下的demo文件夹作为根目录
如果报错检查一下系统环境变量PATH中是否添加了npm的bin路径
react的状态更新是异步的
state = {
//对象
}
//法1
func = () => {
this.setState({
//对象
})
//此处同步获取不到更新状态
}
//法2 对象式的setState
func = () => {
//setState是异步更新,callback回调里的状态是更新后的
//新状态不依赖原状态
this.setState({/*对象更新*/},callback())
}
//法3 函数式的setState
func1 = ()=>{
//state 就是this.state值 props是this.props
//这里也可以有回调函数
//新状态依赖原状态
this.setState(func2(state,props))
}
func2 = (state,props) = > return {/*对象*/};
import {lazy, Suspense} from 'react
//对路由组件使用
const Index = lazy(()=>{import('./Index')})
//用的时候会引入index组件,当请求Index组件在请求中时会显示Suspense组件
让函数式组件使用类式组件的state等具有生命周期
//state Hook 状态
function Index () {
const [状态,更新状态的方法] = React.useState(状态初始化值)
return (/*组件*/)
}
//effect Hook 生命周期
function Index () {
//第一个参数是生命周期函数,第二个是[]表示不检测其他改变,为空表示检测所有改变
//当[]中写入变量时表示检测变量的改变componentDidUpdate
React.useEffect(()=>{
//生命周期函数componentDidMount
return //该函数返回一个函数,这个函数是componentWillUnmount
},[])
return (/*组件*/)
}
//ref Hook
function Index () {
const ref = React.useRef()
return ()
}
import {Fragment} from 'react'
//react解析会丢弃 Fragment组件,该组件只能拥有key属性用于遍历
render(){
return (
)
}
//类似于,但空标签不能写任何属性
render(){
return (
<>
>
)
}
组件问题: 当子组件不使用父组件的状态时,父组件更新render也会触发子组件的render,只要执行setState即使不改变状态也会触发render
//使用PureComponent组件重写shouldComponentUpdata
/*
shouldComponentUpdata(nextProps,nextState){
//参数为下一个即将改变的props或state
return true;//更改组件状态
return false;//不会更改组件状态
}
*/
import {PureComponent} from 'react'
//修改继承
class Index extends PureComponent {
func = ()=>{
//别这样做,PureComponent是浅比较会导致状态不能更新
const obj = this.setState;
obj.name = "honshen";
this.setState(obj);
}
}
//自定义组件中B在A的标签体内不会在页面展示被收集在A的this.props.children中
//想要展示B可以将A组件中加入B组件或 在A组价中添加 {this.props.children}
//当B想要使用A的state时,解决上述问题
{}} /> //很灵活
class A {
render(){
const name = ''
return (
{this.props.children(name)})
}
}
在生产环境有效
//在容易发送错误的子组件的父组件中使用
class Father extends Components{
state = {
hsaError: ''; //准备一个状态,用于标识子组件是否出错
}
static getDerivedStateFromError (error) {
//子组件报错时会触发该函数
//返回一个错误对象
return {hasError: error}
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render(
{this.state.hasError?"Error": }
)
}
//componentDidCatch(){在这个地方统计出错反馈给服务器} //子组件渲染出错时调用类似getDerivedStateFromError
name}/>}} /> //很灵活
class A {
render(){
const name = ‘’
return (
{this.props.children(name)})
}
}
## 错误边界 ErrorBoundary
**在生产环境有效**
```react
//在容易发送错误的子组件的父组件中使用
class Father extends Components{
state = {
hsaError: ''; //准备一个状态,用于标识子组件是否出错
}
static getDerivedStateFromError (error) {
//子组件报错时会触发该函数
//返回一个错误对象
return {hasError: error}
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render(
{this.state.hasError?"Error": }
)
}
//componentDidCatch(){在这个地方统计出错反馈给服务器} //子组件渲染出错时调用类似getDerivedStateFromError