初学者 React


文章目录

  • 初学者 React
  • 一、基本使用
    • 1.JSX
      • 介绍
      • JSX语法规则
    • 2.基本使用语法
  • 二、组件的使用
    • 1.函数式组件
    • 2.类式组件
    • 3.类式组件——state简写
    • 3.类式组件——props
    • 3.类式组件——props简写
    • 4.类式组件——refs
    • 5.类式组件——refs回调函数形式与createRef
    • 6.受控组件的高阶函数和柯里化
  • 三、生命周期
    • 1.旧生命周期
    • 2.新生命周期
    • diff问题
  • 四,脚手架
    • 1.安装
    • 2.样式模块化
    • 五、redux与react-redux的使用
      • 1、redux的使用
      • 2、react-redux的使用
        • 合并reducer
        • UI组件与容器组件可以合并为一个文件
        • 连接
    • 六、Refs详解
    • 导出文件名

一、基本使用

1.JSX

介绍

jsx解决创建虚拟dom太繁琐,用原生js操作创建虚拟dom太复杂,用jsx方便于标签嵌套。虚拟DOM就是一个Object类型的对象。
不用模板字符串: 因为模板字符串是真实DOM
JSX(JavaScriptXML)
XML是早起用于存储传输数据
JSON——》代替XML

JSX语法规则

  1. 定义虚拟DOM是,不要引号
  2. 标签中混入js表达式时要用{}
  3. 样式的类名制定不要用class,要用className
  4. 内联样式:style不能是一个string,用{{key: name}}
    style:{{color: ‘#ffff’, fontSize: “20px”}} {color: ‘#ffff’, fontSize: “20px”}是一个对象,外面的{}表示里面是js语句
  5. 虚拟DOM必须只有一个根标签
  6. 标签必须闭合
  7. 标签首字母:
    (1)若小写字母开头,则将标签转为html中同名元素,若html中午与标签对应的同名元素则报错
    (2)若大写字母开头,react会渲染对应的组件,若组件未定义,则报错

2.基本使用语法

代码如下:

<!-- 引入babel,用于将jsx转为js --><div id="test"></div><script type="text/babel">const VDOM = <h2>无需引号</h2>//这里不用引号是因为script标签里用的babel,将jsx转换为jsReactDOM.render(VDOM, document.getElementById('test')); //将VDOM渲染到test中,且需要一个盒子</script>

二、组件的使用

1.函数式组件

代码如下:

<script type="text/babel">function Demo() {console.log(this) //此处的this是undefined,因为babel编译后开启严格模式,否则此时应该指向windowreturn <h2>函数式组件</h2>}//渲染组件到页面ReactDOM.render(<Demo/>, document.getElementById('test'))/// React解析组件 标签,找到了Demo组件/// 发现组件是使用函数定义的,随后调用该函数,剪个返回的虚拟DOM转为真实DOM,渲染到页面中// demo() {//         //bebal开启了严格模式禁止自定义的this指向window,这里的this指的是undefined//         console.log(this.state.isHot)//     }
</script>

2.类式组件

代码如下:

/// 创建类式组件//必须要继承一个React中的Component//必须要有render//render 必须要有返回值class MyComponent extends React.Component {constructor(props) {//在构造器里初始化状态,并且改变this指向//constructor只调用一次super(props)// super(props)的作用:构造器完全可以省略,但是如果不省略,props也不接不传,通过this访问props会undefined,// 构造器开发时几乎不会用this.state = {isHot: true,wind: '大风'}this.demo = this.demo.bind(this); //解决this指向问题(bind:一是生成新的函数,一是改变this),右侧的demo是从原型链上找到的,左侧上的是挂在自身上的demo}render() {//调用1+n次,n是状态的更改//render中的this,是MyComponent是实例对象const {isHot, wind} = this.state;//这里的this.demo 首先要先找挂在自身的方法,如果没有再找原型链return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热' : '寒冷'}, {wind}</h2>}demo() {//点几次调用几次//这里的this指的是undefined,只有通过实例调用demo时它的this才会是实例对象,//render()中的this.demo不是通过实例调用的//类中方法this的指向:类中所有的方法都开启了局本严格模式,所以不能指向window,所以为undefined//由于demo是作为onclick的回调,所以不是调用类中的方法,而是直接调用堆中的函数,而又因为这个方法是类的方法被开启为局部严格模式,所以this为undefinedconsole.log(this.state.isHot)const isHot = this.state.isHot;// state状态中的数据,React不支持直接更改,要使用内置API更改setState!!!!!!!!//且更新是一种合并不是替换this.setState({isHot: !isHot}) //成功}}//渲染组件到页面ReactDOM.render(<MyComponent/>, document.getElementById("test3"));/*执行了ReactDOM.render(<MyComponent/>...发生了什么?1、React解析组件标签,找到来了组件2、发现组件是用类定义的,然后new出来该类的实例并通过该实例调用到原型上的render方法3、将render返回的虚拟DOM转为真是DO。呈现在页面中*/

3.类式组件——state简写

state是指组件内部自身的值

<div id="test"></div>
<script type="text/babel">//创建组件class Simple extends React.Component {//初始化状态,类中可以直接赋值,且不能在前面加变量声明state= {isHot: false, wind: '清风'}render() {const {isHot, wind} = this.statereturn <h1 onClick={this.Weather} className={isHot ? 'active' : 'actived'}>今天天气:{isHot ? '炎热' : '凉爽'}, {wind}</h1>}//赋值语句加箭头函数//自定义方法中this为undefined:1,强制绑定this,(bind()), 2,箭头函数Weather = ()=>{const isHot = this.state.isHot;this.setState({isHot:!isHot})}}//渲染组件到页面上ReactDOM.render(<Simple/>, document.getElementById('test'))
</script>

3.类式组件——props

props是指外部传入类式组件内部的值

<div id="test"></div>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">class Demo extends React.Component {render() {const {name, age, sex}  = this.props;return (<ul><li>姓名:{name}</li><li>年龄:{age}</li><li>性别:{sex}</li></ul>)}
}//props只读//类型与必选Demo.propTypes = {//PropTypes的类型为了避开关键字,所以大多小写name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,//不能用function,因为function是一个关键字,所以传func,speak: PropTypes.func}//默认值Demo.defaultProps = {sex: '喵喵喵',age: 19}let obj = {name: "S",age: 23,sex:"女"}//渲染组件到页面//批量传递props,也就是批量传递标签属性ReactDOM.render(<Demo {...obj}/>, document.getElementById('test'))//进行类型限制、进行必传行限制、进行默认值限制ReactDOM.render(<Demo name="tom" age={22} sex="男" speak={speak} />, document.getElementById('test2'))function speak() {console.log('正在说话')}
</script>

3.类式组件——props简写

<script type="text/babel">//创建组件class Person extends React.Component {//props只读//类型与必选static propTypes = {//PropTypes的类型为了避开关键字,所以大多小写name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,//不能用function,因为function是一个关键字,所以传func,speak: PropTypes.func}//默认值static defaultProps = {sex: '喵喵喵',age: 19}// state= {name: 'tome', age: 18, sex: '女'}render() {const { name, age, sex, speak } = this.props;return (<ul><li onClick={speak}>姓名:{name}</li><li>性别:{age + 1}</li><li>年龄:{sex}</li></ul>)}}let obj = {name: "S",age: 23,sex: "女"}//渲染组件到页面//批量传递props,也就是批量传递标签属性ReactDOM.render(<Person {...obj} />, document.getElementById('test'))//进行类型限制、进行必传行限制、进行默认值限制ReactDOM.render(<Person name="tom" age={22} sex="男" speak={speak} />, document.getElementById('test2'))function speak() {console.log('正在说话')}</script>

4.类式组件——refs

ref就是把自身节点存入一个容器

<script type="text/babel">class Person extends React.Component {// static propsTypes = {// }// static defaultProps = {// }//展示左侧输入框的数据showData = () => {const {input1} = this.refs;alert(input1.value)}showData2 = ()=>{const { input2 } = this.refs;alert(input2.value)}// ref用来代替id是一个标识// 字符串的ref存在一些效率上的问题,写的过多之后会有问题//使用其它两种render() {return (<div><input ref="input1" type="text" placeholder="点击按钮提示数据"/><button ref="button100" onClick={this.showData}>点击按钮</button> <input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>   </div>)}}ReactDOM.render(<Person/>, document.getElementById('test'))</script>

5.类式组件——refs回调函数形式与createRef

createRef比较麻烦,所以还是经常用内联样式

<script type="text/babel">class Demo extends React.Component {myRef = React.createRef(); //调用后返回一个容器,该容器可以存储被ref所标识的节点,该容器是专人专用的也就是说只能存一个//展示左侧输入框的数据showData = () => {const {input1} = this;console.log(this.myRef.current.value)alert(input1.value)}showData2 = () => {const { input2 } = this;alert(input2.value)}//ref就是把自身节点存入一个容器//回调形式的ref//注释掉的内联样式的ref会被执行两次://这是因为状态更改之后重新调用render,之前的内联函数执行完被释放了,所以这里的函数就是一个新函数了,//因为不确定之前释放的函数做了什么,所以要先清空,所以传了一个null,然后再传入自身节点//但是无关紧要,所以大多数还是用内联saveInput= (c)=> {this.input1 = c}render() {return (<div>{/*<input ref={c=>this.input1 = c} type="text" placeholder="点击按钮提示数据" />*/}<input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" /><button ref="button100" onClick={this.showData}>点击按钮</button><input onBlur={this.showData2} ref={c =>this.input2 = c} type="text" placeholder="失去焦点提示数据" /><input ref={this.myRef} type="text"/></div>)}}ReactDOM.render(<Demo/>, document.getElementById("test"))</script>

6.受控组件的高阶函数和柯里化

柯里化可以让我们给一个函数传递较少的参数,得到一个已经记住了某些固定参数的新函数,这就是柯里化的核心。在柯里化内部就是使用闭包,对函数的参数进行缓存。柯里化让函数变得更灵活,因为我们可以通过一个函数生成一些细粒度更小的函数。这么做的目的是为了在后续函数组合的时候在使用。柯里化可以把多元函数转换成一元函数,目的是可以组合使用函数产生强大的功能
原文链接:https://blog.csdn.net/weixin_33503186/article/details/112049619

<script type="text/babel">//发生事件的元素刚好是要操作的元素就不要用ref//收集表单数据// react没有vue的双向数据绑定,需要自己用onChange去写//受控组件类似vue双向绑定,而且不用ref,所以一般用这种class NotContral extends React.Component {state = {username: '',password: ''}//保存表单数据到状态中//这就是函数的柯里化技术:两个函数里的dataType和event两个参数最后集中处理saveFormData = (dataType)=>{//render首次直接将saveFormData的返回值给onChange,也就是一个匿名函数,//当onChange触发时,调用的其实是这个匿名函数,所以react会传event给这个匿名函数//这是个高阶函数/*高阶函数满足条件:(promise,setTimeOut,arr.map())1.若A函数接收的参数是一个函数,那么这个A就是高阶函数2.若A函数,调用的返回值是一个函数,那么A就是高阶函数函数的柯里化:通过函数连续调用继续返回函数,实现多次接受参数最后统一处理的编码方式*/return (event)=>{console.log(dataType, event.target.value)this.setState([dataType], event.target.value)}}//不用柯里化的实现方式saveFormData = (dataType, event)=>{this.setState({[dataType]: event})}submit = (event) => {event.preventDefault(); //阻止表单默认跳转操作const { username, password } = this.state;console.log(username, password)}render() {return (<form onSubmit={this.submit}>{/*不用柯里化*/}用户名:<input type="text" onChange={event=>this.saveFormData('username', event.target.value)} name="username" placeholder="请输入用户名" />{/*用柯里化*/}用户名:<input type="text" onChange={this.saveFormData('username')} name="username" placeholder="请输入用户名" />密码:<input type="password" name="password" onChange={this.saveFormData('password')} placeholder="请输入密码" /><button>登录</button></form>)}}ReactDOM.render(<NotContral />, document.getElementById('test'))</script>

三、生命周期

1.旧生命周期

分为三个阶段:
1、初始化阶段: 由ReactDOM.render()触发 ----------- 初次渲染
(1)Constructor()
(2)componentWillMount()
(3)render()
(4)componentDidMount() ====>常用(一般在这个钩子中做一些出初始化的事:开启定时器、发送网络请求、订阅消息)
2、更新阶段: 由组件内部this.setState()或父组件render触发
(1)shouldComponentUpdate()
(2)componentWillUpdate()
(3)render()
(4)componentDidUpdate()
3、卸载结算:由ReactDOM.unmountComponentAtNode()触发
(1)componentWillUnmount() ===>常用(一般在这个钩子中做一些收尾的事:关闭定时器、取消订阅消息)

附:网上找到的图,做了一些注释

2.新生命周期

在新生命周期中componentWillMount,componentWillUpdate和componentWillReceviceProps要在前面加上UNSAFE前缀(后面会废弃)

原因:

新提出了两个生命周期钩子,但是实际中用的很少:
getDerivedStateFromProps() 从props中得到一个派生的状态,让state无论什么时候都取决于props,可以使用但不是必须使用,很少用,用的时候会导致代码冗余。
getSnapshotBeforeUpdate(){
return 状态;
}
获得更新前的快照,有一些数据是要在更新前获取的。用法不常见。在componentDidUpdate()中接受三个参数非别是更新前的props,更新前的state和快照返回的值。

diff问题

四,脚手架

1.安装

主要是一因为安装脚手架的时候遇到了报错比如phthon之类的错
所以要先安装yarn


npm install -g yarnyarn global add create-react-appcreate-react-app my-app

2.样式模块化

五、redux与react-redux的使用

redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。
使用情况:
同一个state需要在多个Component中共享
需要操作一些全局性的常驻Component,比如Notifications,Tooltips等
太多props需要在组件树种传递,其中大部分只是为了传给子组件
业务太复杂导致Component文件太大,可以考虑将业务逻辑拆出来放到Reducer中
过程:
应用的state统一放到 里面维护,当需要修改state的时候,dispath一个action给reducer,reducer算出新的state后,再将state发布给事先订阅的组件。

1、redux的使用


reducer的本质是一个函数,接收:preState,action,返回加工后的状态
reducer被第一次调用时,是store自动触发的,
传递的preState是undefined,
传递的action是:{type:'@@REDUX/INIT_a.2.b.4}

API:
store.subscribe(用于index.jsx文件夹中,作用为只要store中状态更新就render组件,也可用于组件中,但组件中要重复写,所以还是要写在入口文件中)因为Dom的diff算法,所以不会引起大规模的重绘重排

store.subscribe(()=>{
ReactDOM.render(,document.getElementById(‘root’))
})

createStore(引入createStore,专门用于创建redux中最为核心的store对象)

import {createStore} from ‘redux’
//引入为Count组件服务的reducer
import countReducer from ‘./count_reducer’
//暴露store
export default createStore(countReducer)

store.dispatch(给store派发一个action对象,store接受action之后传给reducer,reducer接收action对象后根据type类型对状态进行操作,并返回值。在组件中通过store调用状态)

store.dispatch(createIncrementAction(value*1))
store.getState()

异步action
同步action,就是指action的值为Object类型的一般对象
异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
因为异步action返回的是函数,而reduce默认接收的是对象,所以这时要通过一个中间件进行操作
import thunk from ‘redux-thunk’
引入 applyMiddleware中的redux,这个中间件
这个中间件的意义就在于它会告知store,先不要把action传给reducer,等异步任务执行完返回对象时再传给reducer
//引入redux-thunk,用于支持异步action

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {return (dispatch)=>{setTimeout(()=>{dispatch(createIncrementAction(data))},time)}
}

2、react-redux的使用

合并reducer

combineReducers

const AllReducers = combineReducers({he: countReducer,ren: personReducer
})

如果有多个reducer,则要在store.js中合并reducer,合并后的reducer,在store中以对象的形式存在。
combineReducers传入的对象就是redux中要保存的redux对象。

UI组件与容器组件可以合并为一个文件

如何创建一个容器组件————靠react-redux 的 connect函数
connect(mapStateToProps,mapDispatchToProps)(UI组件)
-mapStateToProps:映射状态,返回值是一个对象
-mapDispatchToProps:映射操作状态的方法,返回值是一个对象容器

组件的主要代码

export default connect(
state=>({person: state.ren, count: state.he}),
//state是状态,uI组件是容器组件的字组件所以ui组件中使用状态需要this.props.person
{ add: createAddPersonAction}
//这是行为
)(Person) //Person:这个Person,将容器组件与ui组件连接到一起

步骤:(1).定义好UI组件—不暴露
(2).引入connect生成一个容器组件,并暴露,写法如下:
connect(
state => ({key:value}), //映射状态
{key:xxxxxAction} //映射操作状态的方法
)(UI组件)
(4).在UI组件中通过this.props.xxxxxxx读取和操作状态

无需自己给容器组件传递store,给包裹一个即可。
使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作

连接

容器组件要连接UI组件与store,
连接UI组件通过react-redux中的connect()方法即可连接,
连接右手的store不能通过improt引入要通过App.js中的组件传入

{/* 给容器组件传递store */}

但是如果有多个组件就会出现代码冗余的现象,这时要在index.jsx入口文件里调用Provider,这样就不需要在App.jsx中传递store了。

import { Provider } from ‘react-redux’ //Provider可以让所有容器组件自动传入store不需要自己每次都
这里是引用

<Provider store={store}>< App /></Provider>,

在react-redux中:
//检测redux中状态的改变,若redux的状态发生了改变则重新渲染app组件
// react-redux 不用检测状态的改变,容器组件已经有了检测的能力
// store.subscribe(()=>{
// ReactDOM.render(, document.getElementById(‘root’))
// })
以上这段监测react-redux状态重新渲染app组件的能力可以省略,因为react-redux中已经进行监测了

参考:
https://segmentfault.com/a/1190000015367584
react 官网

六、Refs详解

参考自掘金大佬 原文链接 https://juejin.cn/post/6844903809274085389

导出文件名

导出文件名2022/02/03,文件名时间之间的 / 自动转换成 - 。因为excel 根本就不支持 / 啊。。。。。

About React相关推荐

  1. react非常适合入门者学习使用的后台管理框架

    项目简介 该项目提供一个非常简洁的后台管理ui界面,非常适合初学者学习使用.项目结构: 项目地址:GitHub项目地址 技术栈 - react - antd - react-router-dom - ...

  2. 在 react 里使用 antd

    在 react 里使用 antd 在 powershell 里npm i antd 引入方式: import '../node_modules/antd/dist/antd.css'

  3. 在React Hook里使用history.push跳转

    在React Hook里使用history.push跳转 react hook里用不了this.props.history的解决方法 首先引入 import { useHistory } from ' ...

  4. 在react hook里使用mobx(配置mobx依赖)

    在powershell里安装依赖 (直接npm i mobx或者npm i mobx-react是会报错的) npm i mobx mobx-react --save save是下载到"de ...

  5. React router 的 Route 中 component 和 render 属性理解

    React router 的 Route 中 component 和 render 属性理解 Route 标签的三个互斥属性 render.component.children Route 就是用来匹 ...

  6. react 子组件获取变量属性值

    刚刚遇到一个问题:子组件属性值绑定了变量,但是在子组件的componentDidMoiunt中拿到的值始终是undefinded.如下: 1 <PieInfo 2 title='有效病案' 3 ...

  7. 超简单的react和typescript和引入scss项目搭建流程

    1.首先我们先创建一个react项目,react官网也有react项目搭建的命令 npx create-react-app my-app cd my-app 2.安装我们项目需要的样式依赖,这个项目我 ...

  8. React Native之ViewPagerAndroid跳转页面问题

    前言: 网上目前react-native的教程较少,加上许多帖子还是用的ES5(2015年6月已发布ES6标准),有些细节很难找到答案,这里把遇到的问题做一个分享,让学习者尽量少踩坑. 出现问题: 1 ...

  9. http状态404 vscode_VS Code 调试完全攻略(5):基于浏览器的 React 应用

    每日前端夜话第344篇 翻译:疯狂的技术宅 作者:Charles Szilagyi 来源:charlesagile 正文共:1750 字 预计阅读时间:7 分钟 这次我们来研究怎样把调试器连接到用 C ...

  10. react 组件连动效果_react-redux应用之独立组件联动实例

    准备工作 先导入必要的库资源 import React, { Component, PropTypes } from 'react' import ReactDOM from 'react-dom' ...

最新文章

  1. QT写入cmd命令并且调用,以及指定路径新建文件夹
  2. MessageDigest简介
  3. ISA2006系列之三 详解防火墙的三种客户端(上)
  4. 基于消息队列的UDP并发服务器v1
  5. Jmeter 分布式测试完整实践过程(部署成功)
  6. elasticsearch kabana中创建索引
  7. console.log(12.toString())为啥会报错呢?
  8. 互联网小团队创业 第三集 创业准备易犯的错误 汪华
  9. c语言完整表白程序代码,C语言告白代码,一闪一闪亮晶晶~
  10. 地籍测绘成图软件南方cass9.0支持AutoCad2010【安装文件和视频教程】
  11. java jcmd,jcmd命令用法
  12. 随e行wlan v9.2.0930
  13. petalinux 建立工程两种方式
  14. Js坐标转换器-百度地图坐标转腾讯地图坐标
  15. 蔡凯龙:跨界是一种寻求人生宽度的方式
  16. 一般信道容量迭代算法c语言,(信息论编码)信道容量迭代算法
  17. html获取qq高清头像
  18. 如何开发一个人脸识别,人脸识别系统,人脸识别考勤系统毕业设计毕设作品
  19. 国内可用的 ChatGPT
  20. PDF转PPT怎么转?一键完成格式转换,太方便了

热门文章

  1. distribute-list
  2. 金蝶云星空简单账表动态列名汇总
  3. Activemq安装和控制台
  4. 【线性模型引论】王松桂著 课后习题3.9参考答案
  5. 豪横卡塔尔!疯狂世界杯
  6. 解决金仓数据库KingbaseES创建serial列并将其设置为主键约束,同时copy两条及以上数据时报错的问题
  7. cfml 组件(cfc)示例源代码
  8. 分享一款网页端CF活动助手 网页打开一键领取所有CF活动
  9. 超级病毒“xxshenqi.[XX神器]”到底有多牛
  10. 初学者零基础如何成为漫画师?该怎么做?