react全家桶

react全家桶

体验 React

React 从诞生之初就是可被逐步采用的,因而你可以按需引入或多或少的 React 特性。不管你是想体验下 React,用它给简单的 HTML 页面增加一点交互,还是要开始一个完全由 React 驱动的复杂应用,该章节内容里的链接都能帮你快速开始。

在线体验

如果你对体验 React 感兴趣,可以尝试在线代码编辑器。从 CodePenCodeSandboxGlitch, 或者 Stackblitz 开始一个 React 版本的 Hello World 模版。

如果你喜欢使用自己的文本编辑器,也可以下载这个 HTML 文件,然后编辑文件内容,最后再用浏览器从本地文件系统打开文件,预览页面效果。注意:这个文件中包含一个低效率的运行时代码转换脚本,所以我们推荐仅在简单的演示项目中使用。

在网站中添加 React

你可以立即在 HTML 文件中添加 React,然后选择逐渐拓展它的应用范围,或只在一些动态小部件中使用它。

创建新的 React 应用

当你刚开始一个 React 应用时,通过 HTML 的 script 标签引入 React 依然是最好的选项,因为这能让你的项目立即启动。

但随着应用越来越大,你可能会需要更加集成化的安装方式。我们推荐了一些 JavaScript 工具链,它们适合大型应用。它们只需很少甚至零配置,就能让你充分利用丰富的 React 生态。立即尝试

JSX语法糖

官方提示: React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。

  1. 使用js表达式需要加括号{}: 表达式是一个值

    const name = 'Josh Perez';
    const element = <h1>Hello, {name}</h1>;
    ReactDOM.render(
    	element,
     	document.getElementById('root')
    );
    //等效的两种写法
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    //React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
    // 注意:这是简化过的结构
    const element = {
      type: 'h1',
      props: {
        className: 'greeting',
        children: 'Hello, world!'
      }
    };
    
  2. 属性使用

    内联样式使用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 = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);
  1. 标签

    //标签必须关闭否则报错
    <input />
    //不要使用自定义标签,除非你想使用组件,且组件名首字母需要大写
    //react识别标签如果是小写字母开头则将其转为html标签如果没有与之对应的标签则报错
    <good></good>
    //首字母大写则是组件,如果没有该组件则报错
    <Good></Good>
    
  2. 循环

    const element = (
      <ul>
        {
                //item中需要有id属性赋予key唯一值
            data.map(item,index)=>{
                return <li key={item.id}>{item}</li>
            }
        }
      </ul>
    );
    

react开发工具

官方调试工具: 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 <h2>demo</h2>
}
ReactDOM.render(<Dome/>,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 <h1>honshen</h1>
    }
}
//调用了new Person得到实例对象,且调用render方法,方法中的this指向其实例对象
ReactDOM.render(<Person/>,document.getElementById('demo'))

组件三大属性

state

constructor (prpos){
    this.state = {} //初始化state
    this.setState() //更新状态
    this.state.name //读取name
}

props

<B title="abd" />

class B extends Components{
    //读取属性
    this.props
}

ref

//ref类似于getElementById
class B extends Components{
    func = () => {
      const  {scanIn} = this.refs
      scanIn.value //输入框的值
       this.input.value //获取输入的值
    }
    render(
    <input ref="scanIn" />
    <input ref={(input)=>{this.input = input}} /> //推荐
    )
}

高阶函数–柯里化函数

//不使用柯里化函数
function func(event,data) {
    //函数体
}
<input onChange={(event)=>{this.func(event,data)}}
 //柯里化函数
 function func (data){
    return (event)=>{
        //函数体
    }
}
<input onChange={this.func(data)}

React脚手架

//全局安装
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: {'^请求路径':''}
})
)
}

组件通信

父子组件通信

//父组件直接传递数据给子组件
<Son data={this.state}/>
//子组件接收数据
const {data} = this.props

状态提升

//子组件将state提升到父组件里
//子组件修改父组件的数据
change(){}
<Son change={this.change} />

消息订阅与发布

订阅消息:

1. 消息名
2. 消息发布
//使用库 PubSubJs
npm i pubsub-js --save
//在componentDidMount(){}中订阅消息
PubSub.subscribe('消息名',(_,data)=>{
    //处理
})

Redux状态管理js

集中管理组件中多个共享的状态

谷歌浏览器插件: 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必须使用纯函数:同一个输入只有同一个输出

组件通信 Context

适用于组组件与后代组件通信

//在组组件中创建上下文对象Con是一个容器对象
const Con = React.createContext()
const {Provider} = Con
const {Consumer} = Con
//子组件被上下文包裹
<Provider value={data}>
      <Son /> //在son的内部组价都能收到data但必须声明使用,通过后代组件的this.context
</Provider>

//在son组件内部想要使用context的组件需要声明使用=类式组件
static contextType = Con
this.context; //获取context对象

//也可以使用这样的方式在需要使用数据的地方--函数组件
<Consumer>
    {
        value => {
            //函数
            //返回一个组件
        }
    }
</Consumer>

SPA和React路由

SPA: 单页面应用,点击页面不会刷新只会做局部更新

react路由

import 'react-router-dom';
<BrowserRouter>
<HashRouter>
<Route>
<Redirect>
<Link>	//默认是push,点击后向栈顶加入,当使用 <Link replace={true} />时不能回退历史记录
<NavLink>
<Switch>
{//注册路由,模糊匹配}
<Route path="路径" component={组件名} />
{//严格匹配,不能随便开}
<Switch>
    <Route exact={true} path="路径" component={组件名} />
</Switch>
{//路由组件会默认收到一些props, this.props查看一下
//如果多个路由的path一致则同时展示两个组件,但这种不好,建议合并两个为一个组件
//路由较多时使用<Switch>
/*react样式丢失问题: 当在多级路由路径下刷新时,index.html中引入的css样式会请求相应css但路由所在路径刷新导致请求失败react会返回index.html的内容所以css请求返回的是index.html
    解决方法: 1. 引入css使用根路径
    		2. 使用%PUBLIC_URL%作为样式的路径,推荐
    		3. 使用HashRouter
*/}
 //当模糊匹配失败时
<Switch>
    <Route path="" /
    <Redirect to="" ///写在所有路由的最下方
</Switch>

react嵌套路由

//例如请求 /home/me 先匹配/home 当/home/me是Home组件

//组件1中
<Switch>
    <Route path="/home/login"/>
    <Route path="/home/me" component={Me}/> //匹配成功
    <Redirect to="home/me" /> //写在所有路由的最下方
</Switch>

//app中
<Switch>
    <Route path="/index"/>
    <Route path="/home" component={Home}/> //匹配成功
    <Redirect to="index" /> //写在所有路由的最下方
</Switch>

路由传参

//1. 路径传参params 路由占位符 :
<Link to={`/index/${id}/${info}`} /> //传参
<Route path = "/index/:id/:info" component={Index}></Route> //在注册路由时声明接收参数this.props.match.params中能够拿到id和info

//2. 传递search参数
<Link to={`/index?id=${id}&info=${info}`} /> //传参
<Route path = "/index/" component={Index}></Route> //无需申明接收参数,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传参不会
<Link to={{pathname: '/index',state:{id:1,info:2}}} />
<Route path = "/index/" component={Index}></Route> //无需申明接收参数在组件的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组件使之可以使用路由组件的一些函数

HashRouter与BrowserRouter区别

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可以用于解决一些路径错误相关的问题。

Ant-design 蚂蚁设计

按钮及icon

//按钮
import 'antd/dist/antd.css';
import { Button } from 'antd';
<Button type="primary">Primary Button</Button>
<Button type="dashed" shape="circle" icon={<SearchOutlined />} /> //引入图标

//图标
import 'antd/dist/antd.css';
import {
  HomeOutlined,
  SettingFilled,
  SmileOutlined,
  SyncOutlined,
  LoadingOutlined,
} from '@ant-design/icons';
<HomeOutlined />
<SettingFilled />
<SmileOutlined />
<SyncOutlined spin />
<SmileOutlined rotate={180} />
<LoadingOutlined />

//样式按需引入
官网中: 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路径

扩展

setState的两种写法

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 {/*对象*/};

懒加载 Lazy_load

import {lazy, Suspense} from 'react
//对路由组件使用
const Index = lazy(()=>{import('./Index')})
//用的时候会引入index组件,当请求Index组件在请求中时会显示Suspense组件
<Suspense fallback={/*可以写正在加载中的组件名,这个组件必须不能是懒加载组件*/}>
      <Router>
        <Index />
        <Login />
      </Router>
</Suspense>

钩子 Hooks

让函数式组件使用类式组件的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 (<input type="text" ref={ref} /></inpu>)
}

多级嵌套解决 Fragment

import {Fragment} from 'react'

//react解析会丢弃 Fragment组件,该组件只能拥有key属性用于遍历
render(){
    return (
    <Fragment>
            <div />
    </Fragment>
    )
}
//类似于,但空标签不能写任何属性
render(){
    return (
    <>
       <div />
    </>
    )
}

组件优化 PureComponent

组件问题: 当子组件不使用父组件的状态时,父组件更新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);
  }  
}

插槽技术 renderProps

//自定义组件中B在A的标签体内不会在页面展示被收集在A的this.props.children中
<A>
    <B /> //想要展示B可以将A组件中加入B组件或 在A组价中添加 {this.props.children}
</A>

//当B想要使用A的state时,解决上述问题
<A render{(name)=>{<B name={name}/>}} /> //很灵活
 
class A { 
   render(){
        const name = ''
         return (
                 {this.props.children(name)})   
        }
    }

错误边界 ErrorBoundary

在生产环境有效

//在容易发送错误的子组件的父组件中使用
class Father extends Components{
    state = {
        hsaError: ''; //准备一个状态,用于标识子组件是否出错
    }
 static getDerivedStateFromError (error) {
     //子组件报错时会触发该函数
     
     //返回一个错误对象
     return {hasError: error}
 }   
  componentDidCatch(error, errorInfo) {
    // 你同样可以将错误日志上报给服务器
    logErrorToMyService(error, errorInfo);
  }
render(
	{this.state.hasError?"Error":<son/>}
)
}
//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":<son/>}
)
}
//componentDidCatch(){在这个地方统计出错反馈给服务器} //子组件渲染出错时调用类似getDerivedStateFromError
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hon_shen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值