• React入门(上)


    本篇博客为本人学习react的入门记录笔记,参考资料来之柴柴老师在b站分享的react学习视频,仅供学习参考学习视频是来自于b站的:柴柴_前端教书匠

    视频链接:React入门到实战(2022全网最新)_哔哩哔哩_bilibiliicon-default.png?t=M85Bhttps://www.bilibili.com/video/BV1Z44y1K7Fj/?spm_id_from=333.337.search-card.all.click&vd_source=8eaa56c0356b7a86f2c10571ee56b9f2

    目录

    使用脚手架创建一个简单的react项目

    jsx入门

    jsx简介

    JSX中使用js表达式

    JSX列表渲染

    jsx条件渲染

    jsx中的样式处理

    动态类名控制

    jsx的注意事项

    vscode格式化插件配置

    组件事件绑定

    函数组件的创建和渲染

    类组件的创建和渲染

    事件绑定

    获取事件对象e

    传递自定义参数

    组件状态(类组件)

    this问题说明

    react的状态(state)不可变

    表单处理


    使用脚手架创建一个简单的react项目

    打开命令行窗口 ,输入命令:(如果是使用vscode开发工具的,记得要以管理员的身份打开这个vs code):

    npx create-react-app react-basic

    前提:想要成功执行这个命令,需要自己的电脑中安装了这个node的环境。

    创建好的项目的结构:把src文件夹下没有用到的文件删除,只保留下面几个主要的文件:

    最后app.js与index.js的代码如下(进行了删除)

    1. function App() {
    2. return (
    3. "App">
    4. app
  • );
  • }
  • export default App;
    1. import React from 'react'; //框架的核心包
    2. import ReactDOM from 'react-dom/client'; //专门做渲染相关的包
    3. import './index.css'; //应用的全局样式文件
    4. import App from './App'; //引入根组件,一切组件化的开始
    5. //开始渲染根组件 渲染到哪里去?渲染到一个id为 root 的dom节点上 实际上打开这个public中的index.html文件中就可以看见一个div的id为root,
    6. //然后进行挂载,大致的流程就是 自动的对root根组件进行渲染挂载
    7. const root = ReactDOM.createRoot(document.getElementById('root'));
    8. root.render(
    9. //把严格模式节点需要去掉,不然在这个模式下会影响我们的useEffect的时机,这个模式会检查额外的副作用会让我们的useEffect执行两次,这个是react18的特性
    10. //
    11. //
    12. );

    启动项目:或者是使用命令启动 : npm run start 或者是 yarn start  

     然后就会打开浏览器显示如下:

    jsx入门

    jsx简介

    JSX是 JavaScript XML(HTML)的缩写,表示在 JS 代码中书写 HTML 结构

    作用:在React中创建HTML结构(页面UI结构)

    优势:

    1. 采用类似于HTML的语法,降低学习成本,会HTML就会JSX

    2. 充分利用JS自身的可编程能力创建HTML结构

    注意:JSX 并不是标准的 JS 语法,是 JS 的语法扩展,浏览器默认是不识别的,脚手架中内置的 @babel/plugin-transform-react-jsx 包,用来解析该语法

    JSX中使用js表达式

    语法:{ JS 表达式 } 注意这个{}里面只能写表达式,不能写语句!!!

    可以使用的表达式:

    • 字符串、数值、布尔值、null、undefined、object( [] / {} )

    • 1 + 2、'abc'.split('')、['a', 'b'].join('-')

    • fn()

    案例演示:在创建的react项目中的app.js文件中写的;

    1. //1.识别我们的常规变量
    2. const name = "react 学习"
    3. //2.原生js中的调用
    4. const getAge = () =>{
    5. return "永远的18";
    6. }
    7. //3.三元运算符(常用)
    8. const flag = false;
    9. function App() {
    10. return (
    11. "App">
    12. {name}

    13. {getAge()}

    14. {flag ? '18':'68'}
  • );
  • }
  • export default App;
  • 特别注意:if 语句/ switch-case 语句/ 变量声明语句,这些叫做语句,不是表达式,不能出现在 {} 中!!

    JSX列表渲染

    react中如何完成列表的渲染? 技术方案:map

    1. //4.创建一个列表 重复渲染的是哪个模板 就return谁,比如我们这里渲染的是一个列表,所以就return一个列表
  • //注意事项:遍历的列表同时需要一个类型为nuber/string 不可重复key 提高diff性能
  • //key不仅仅在内部使用,不会出现在真实的dom结构中
  • const songs = [
  • { id: 1, name: '痴心绝对' },
  • { id: 2, name: '像我这样的人' },
  • { id: 3, name: '南山南' }
  • ]
  • function App() {
  • return (
  • "App">
    • {
    • //重复渲染的是哪个模板就return谁, 比如我们这里渲染的是一个列表,所以就return一个列表
    • songs.map(item =>
    • {item.name}
    • )
    • }
    • );
    • }
    • export default App;
      1. key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用

      2. key 在当前列表中要唯一的字符串或者数值(String/Number)

      3. 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值

      4. 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值

      jsx条件渲染

      作用:根据是否满足条件生成HTML结构,满足条件才进行渲染。

      实现:可以使用 三元运算符逻辑与(&&)运算符

      1. // 来个布尔值
      2. const flag = true
      3. function App() {
      4. return (
      5. "App">
      6. {/* 条件渲染字符串 */}
      7. {flag ? 'react真有趣' : 'vue真有趣'}
      8. {/* 条件渲染标签/组件 */}
      9. {flag ? (this is span) : null}
      10. )
      11. }
      12. export default App

      如果我们遇到了 复杂的多分支的逻辑,那么应该怎么办呢?肯定是不能三元套三元的,这样会导致代码的可读性非常弱。

      原则:模板中的逻辑尽量保持精简 收敛为一个函数,通过一个专门的函数来写分支逻辑,模板中只负责调用。

      1. const getTag = (type)=>{
      2. if(type === 1){
      3. return

        this h1

      4. }
      5. if(type === 2){
      6. return

        this h2

      7. }
      8. if(type === 3){
      9. return

        this h1

      10. }
      11. }
      12. function App() {
      13. return (
      14. "App">
      15. getTag(1)
      16. );
      17. }
      18. export default App;

      jsx中的样式处理

      注意:使用样式处理的时候,需要使用两个{}来进行包裹,第一个{}的作用是为了让第二个{}识别为对象,第二个{}是对象,用来写我们的样式属性。

      1、行内样式 - style (在元素身上绑定一个style属性即可)

      1. function App() {
      2. return (
      3. "App">
      4. 'red' }}>this is a div
      5. )
      6. }
      7. export default App

      2、行内式 - style - 更优写法 (把样式以对象抽离出来)

      1. const styleObj = {
      2. color:red
      3. }
      4. function App() {
      5. return (
      6. "App">
      7. this is a div
      8. )
      9. }
      10. export default App

      3、类名 - className(推荐)(在元素身上绑定一个className属性即可)

      1. .active{
      2. color:blue;
      3. }
      1. import './app.css'
      2. function App() {
      3. return (
      4. "App">
      5. 'active'>测试类名样式
      6. )
      7. }
      8. export default App

      动态类名控制

      样式文件:命名为app.css

      1. .active{
      2. color:blue;
      3. }
      1. import './app.css'
      2. const flag = true;
      3. const style = {
      4. color:'red'
      5. }
      6. function App() {
      7. return (
      8. "App">
      9. 'active' : ''}>测试动态类名

      10. 测试行内样式
      11. );
      12. }
      13. export default App;

       

      jsx的注意事项

      1. JSX必须有一个根节点,如果没有根节点,可以使用<>(幽灵节点)替代

       

      2. 所有标签必须形成闭合,成对闭合或者自闭合都可以

      3. JSX中的语法更加贴近JS语法,属性名采用驼峰命名法 class -> className for -> htmlFor

      4. JSX支持多行(换行),如果需要换行,需使用() 包裹,防止bug出现

      vscode格式化插件配置

      1. 安装vsCode prettier插件

      2. 修改配置文件 setting.json

      1. {
      2. "git.enableSmartCommit": true,
      3. // 修改注释颜色
      4. "editor.tokenColorCustomizations": {
      5. "comments": {
      6. "fontStyle": "bold",
      7. "foreground": "#82e0aa"
      8. }
      9. },
      10. // 配置文件类型识别
      11. "files.associations": {
      12. "*.js": "javascript",
      13. "*.json": "jsonc",
      14. "*.cjson": "jsonc",
      15. "*.wxss": "css",
      16. "*.wxs": "javascript"
      17. },
      18. "extensions.ignoreRecommendations": false,
      19. "files.exclude": {
      20. "**/.DS_Store": true,
      21. "**/.git": true,
      22. "**/.hg": true,
      23. "**/.svn": true,
      24. "**/CVS": true,
      25. "**/node_modules": false,
      26. "**/tmp": true
      27. },
      28. // "javascript.implicitProjectConfig.experimentalDecorators": true,
      29. "explorer.confirmDragAndDrop": false,
      30. "typescript.updateImportsOnFileMove.enabled": "prompt",
      31. "git.confirmSync": false,
      32. "editor.tabSize": 2,
      33. "editor.fontWeight": "500",
      34. "[json]": {},
      35. "editor.tabCompletion": "on",
      36. "vsicons.projectDetection.autoReload": true,
      37. "editor.fontFamily": "Monaco, 'Courier New', monospace, Meslo LG M for Powerline",
      38. "[html]": {
      39. "editor.defaultFormatter": "vscode.html-language-features"
      40. },
      41. "editor.fontSize": 16,
      42. "debug.console.fontSize": 14,
      43. "vsicons.dontShowNewVersionMessage": true,
      44. "editor.minimap.enabled": true,
      45. "emmet.extensionsPath": [
      46. ""
      47. ],
      48. // vue eslint start 保存时自动格式化代码
      49. "editor.formatOnSave": true,
      50. // eslint配置项,保存时自动修复错误
      51. "editor.codeActionsOnSave": {
      52. "source.fixAll": true
      53. },
      54. "vetur.ignoreProjectWarning": true,
      55. // 让vetur使用vs自带的js格式化工具
      56. // uni-app和vue 项目使用
      57. "vetur.format.defaultFormatter.js": "vscode-typescript",
      58. "javascript.format.semicolons": "remove",
      59. // // 指定 *.vue 文件的格式化工具为vetur
      60. "[vue]": {
      61. "editor.defaultFormatter": "octref.vetur"
      62. },
      63. // // 指定 *.js 文件的格式化工具为vscode自带
      64. "[javascript]": {
      65. "editor.defaultFormatter": "vscode.typescript-language-features"
      66. },
      67. // // 默认使用prettier格式化支持的文件
      68. "editor.defaultFormatter": "esbenp.prettier-vscode",
      69. "prettier.jsxBracketSameLine": true,
      70. // 函数前面加个空格
      71. "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
      72. "prettier.singleQuote": true,
      73. "prettier.semi": false,
      74. // eslint end
      75. // react
      76. // 当按tab键的时候,会自动提示
      77. "emmet.triggerExpansionOnTab": true,
      78. "emmet.showAbbreviationSuggestions": true,
      79. "emmet.includeLanguages": {
      80. // jsx的提示
      81. "javascript": "javascriptreact",
      82. "vue-html": "html",
      83. "vue": "html",
      84. "wxml": "html"
      85. },
      86. // end
      87. "[jsonc]": {
      88. "editor.defaultFormatter": "vscode.json-language-features"
      89. },
      90. // @路径提示
      91. "path-intellisense.mappings": {
      92. "@": "${workspaceRoot}/src"
      93. },
      94. "security.workspace.trust.untrustedFiles": "open",
      95. "git.ignoreMissingGitWarning": true,
      96. "window.zoomLevel": 1
      97. }

      错误提示的插件:

      组件事件绑定

      组件化开发是当前前端开发的主流模式。

       

      组件开发中,每一个组件都是一个独立的功能,可以各个组件被重复利用,维护起来也可以在对应的位置进行维护。

      理解:组件实际上就是把一个一个的小功能抽离封装起来,然后像搭积木一样,把这些组件叠加起来,最后形成了一个大的应用,这就是所谓的组件。

      react提供了两种组件,一种是函数组件,一种是类组件。

      函数组件的创建和渲染

      函数组件的创建:

      1. //创建函数式组件
      2. function Hello(){
      3. return
        hello
      4. }
      5. function App () {
      6. return (
      7. "App">
      8. {/* 渲染hello组件,相当于在这里进行了调用 */}
      9. )
      10. }
      11. export default App

      约定说明

      1. 组件的名称必须首字母大写,react内部会根据这个来判断是组件还是普通的HTML标签。

      2. 函数组件必须有返回值,返回的值表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null。

      3. 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的返回值就是对应的内容。

      4. 使用函数名称作为组件标签名称,可以成对出现也可以自闭合。

      类组件的创建和渲染

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. return
        hello
      5. }
      6. //类组件的创建和渲染
      7. class HelloCompoent extends React.Component {
      8. //这个render函数是必须的
      9. render () {
      10. return
        this is class component
      11. }
      12. }
      13. function App () {
      14. return (
      15. "App">
      16. {/* 渲染hello组件 */}
      17. {/* 渲染类组件 */}
      18. )
      19. }
      20. export default App

      约定说明

      1. 类名称也必须以大写字母开头

      2. 类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性

      3. 类组件必须提供 render 方法render 方法必须有返回值,这个返回值表示该组件的 UI 结构

      事件绑定

      函数事件绑定:

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. //创建一个事件(相当于一个方法)
      5. const clickHandler = () => {
      6. console.log('函数组件中的事件被触发了')
      7. }
      8. //绑定事件
      9. return
        hello
      10. }
      11. function App () {
      12. return (
      13. "App">
      14. {/* 渲染hello组件 */}
      15. )
      16. }
      17. export default App

      类组件事件绑定:

      1. import React from "react"
      2. //类组件的创建和渲染
      3. class HelloCompoent extends React.Component {
      4. //事件回调函数(标准写法) 这样写可以避免this指向问题 这样写可以回调函数中的this指向是当前的组件实例对象,如果你不这样写的话是很容易出现this指向不明的
      5. clickHandler2 = () => {
      6. console.log('类组件中的事件被触发了')
      7. }
      8. //这个render函数是必须的
      9. render () {
      10. //在类组件中绑定回调函数,需要使用this关键字来进行调用 this指向当前组件实例
      11. return
        this is class component
      12. }
      13. }
      14. function App () {
      15. return (
      16. "App">
      17. {/* 渲染类组件 */}
      18. )
      19. }
      20. export default App

       

      获取事件对象e

      事件对象e可以用来阻止一些的默认行为

      函数组件获取e对象方式如下:直接在形参中添加e就行

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. //创建一个事件(相当于一个方法)
      5. const clickHandler = (e) => { //函数组件中获取e对象
      6. console.log('函数组件中的事件被触发了', e)
      7. }
      8. return
        hello
      9. }
      10. function App () {
      11. return (
      12. "App">
      13. {/* 渲染hello组件 */}
      14. )
      15. }
      16. export default App

       使用e对象阻止一些默认行为,我们先来看一下什么是默认行为:

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. //创建一个事件(相当于一个方法)
      5. const clickHandler = (e) => {
      6. console.log('函数组件中的事件被触发了', e)
      7. }
      8. }
      9. //类组件的创建和渲染
      10. class HelloCompoent extends React.Component {
      11. //事件回调函数(标准写法)
      12. clickHandler2 = () => {
      13. console.log('类组件中的事件被触发了')
      14. }
      15. //这个render函数是必须的
      16. render () {
      17. //在类组件中绑定回调函数,需要使用this关键字来进行调用
      18. return
        this is Compoent
      19. }
      20. }
      21. function App () {
      22. return (
      23. "App">
      24. {/* 渲染hello组件 */}
      25. {/* 渲染类组件 */}
      26. )
      27. }
      28. export default App

      点击上面的百度:控制台会打印下面的文字并且页面进行跳转:

       我们自己的打印信息被百度的信息进行了覆盖,并且网页也进行了跳转,我们只想让自己的信息打印出来不想跳转,那么如何操作?

       再次点击 百度,看控制台的输出信息,并且发现页面也不会进行跳转了。

      传递自定义参数

      场景:就是我们想在触发事件的时候,传递一些自定义参数,应该怎么操作?

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. //创建一个事件(相当于一个方法)
      5. const clickHandler = (msg) => {
      6. console.log('函数组件中的事件被触发了', msg)
      7. }
      8. //需要在调用的时候传递实参,需要修改函数组件触发的调用方式了 : 改造成箭头函数的调用方式就行
      9. return
        clickHandler('this is msg')}> 点击
      10. {/*之前的调用方式
        点击
        */}
      11. }
      12. function App () {
      13. return (
      14. "App">
      15. {/* 渲染hello组件 */}
      16. )
      17. }
      18. export default App

       如果我们想要既传递 e 又要想要传递自定义参数,那么应该怎么操作?

      1. import React from "react"
      2. //创建函数式组件
      3. function Hello () {
      4. //创建一个事件(相当于一个方法)
      5. const clickHandler = (e,msg) => {
      6. console.log('函数组件中的事件被触发了', e,msg)
      7. }
      8. //需要在调用的时候传递实参,需要修改函数组件触发的调用方式了 : 改造成箭头函数的调用方式就行 并且需要注意形参和实参的顺序
      9. return
        clickHandler(e,'this is msg')}> 点击
        {/* 需要先捕获e然后再传递到绑定的事件中*/}
      10. {/*
      11. 之前不需要传递参数的调用方式
        点击
      12. 之前传递一个自定义参数的调用方式:return
        clickHandler('this is msg')}> 点击
      13. */}
      14. }
      15. function App () {
      16. return (
      17. "App">
      18. {/* 渲染hello组件 */}
      19. )
      20. }
      21. export default App

      总结:

      1、只需要一个额外参数 写法: {clickHandler} -> { () => clickHandler('自定义参数')}

      2、既需要e也需要额外的自定义参数 {(e) => clickHandler(e,'自定义的参数') }

      组件状态(类组件)

      一个前提:在React hook出来之前,函数式组件是没有自己的状态的,所以这里我们先统一通过类组件来进行讲解。

      下面演示一下:初始化状态,获取状态中的值,修改状态中的值。

      下面的写法可以避免this的指向问题,以后在使用react的开发中直接这样写就行,不需要去维护this的指向问题。

      1. import React from "react"
      2. //组件状态 这里使用类组件作为演示
      3. class TestComponent extends React.Component {
      4. //1.定义组件状态 【初始化状态】
      5. state = {
      6. //这里面可以定义各种属性 这些属性全是当前组件的状态
      7. name: '组件状态测试'
      8. }
      9. //5.声明事件回调函数(自定义的)
      10. changeName = () => {
      11. //在事件回调函数中修改组件状态 【修改状态】注意:这里不可以直接做赋值修改 必须通过setState方法来进行修改这个state值
      12. this.setState({
      13. //直接在这个方法中修改state的属性
      14. name: '修改后的name'
      15. })
      16. }
      17. //这个render函数是组件自己携带的方法 3.在render方法中写一些处理逻辑
      18. render () {
      19. return (
      20. this is TestComponent
      21. {/*【读取状态】*/}
      22. 当前组件的name属性为:{this.state.name}
      23. {/*4.定义按钮触发自定义事件 */}
      24. )
      25. }
      26. }
      27. function App () {
      28. return (
      29. "App">
      30. {/* 2.渲染定义的类组件 */}
      31. )
      32. }
      33. export default App

      总结:

      1、编写组件其实就是编写原生的js类或者是函数

      2、定义状态必须通过state实例属性中的方法提供一个对象 名称是固定的就叫做state

      3、修改状态state中的任何属性 都不可以通过直接赋值来进行修改,必须走setState方法 这个方法来自于继承得到的(因为react体系中,'数据不可变')

      4、这里的this关键词很容易出现指向错误的问题,上面的案例写法是最推荐最规范的,是不会出现this的指向问题

      5、当然上面这样来使用状态是比较麻烦的,后面学习了hook就用的都是函数式组件了,但是一些老的项目维护的应该还是类组件,所以这里也是需要学习一下的。

       练习: 写一个count按钮,点击按钮实现按钮中间的数据加一

      1. class Counter extends React.Component {
      2. // 定义数据
      3. state = {
      4. count: 0
      5. }
      6. // 定义修改数据的方法
      7. setCount = () => {
      8. this.setState({
      9. {/* 不能通过++来完成,必须要拿到上一次的值(this.state.count) 然后对其进行处理(+1处理) 再赋值给这个属性 */}
      10. count: this.state.count + 1
      11. })
      12. }
      13. // 使用数据 并绑定事件
      14. render () {
      15. return
      16. }
      17. }

      this问题说明

      这里我们作为了解内容,随着js标准的发展,主流的写法已经变成了class fields,无需考虑太多this问题

      下面演示一种错误的写法:

      1. import React from "react"
      2. class Test extends React.Component {
      3. change(){
      4. console.log(this) //输出的this是undefined 所以此时再去使用this.setState修改数据就会报错
      5. }
      6. render () {
      7. return (
      8. )
      9. }
      10. }
      11. function App () {
      12. return (
      13. "App">
      14. {/* 渲染定义的类组件 */}
      15. )
      16. }
      17. export default App

       如果你非要 change(){}这种写法来定义函数式组件,那么要怎么才能解决这个this指向问题?如下:

      1. import React from "react"
      2. class Test extends React.Component {
      3. //在几年之前的react的修正this指向,就是经常这么操作的---手动修正
      4. constructor(){
      5. super();
      6. //使用bind强行修正我们的this指向 相当于在类组件的初始化阶段就可以把【回调函数的this】修正到永远指向当前实例对象
      7. this.change = this.change.bind(this);
      8. }
      9. change(){
      10. console.log(this) //输出的this是组件的实例属性
      11. }
      12. render () {
      13. return (
      14. )
      15. }
      16. }
      17. function App () {
      18. return (
      19. "App">
      20. {/* 渲染定义的类组件 */}
      21. )
      22. }
      23. export default App

      另一种解决这种this指向的问题:

      1. import React from "react"
      2. class Test extends React.Component {
      3. change(){
      4. console.log(this) //输出的this是组件的实例属性
      5. }
      6. render () {
      7. return (
      8. {/*如果不通过constructor做修正,那么我们可以直接在事件绑定的位置通过箭头函数的写法 --> 这种写法是直接沿用父函数(render)中的this 这个函数的父函数是render,这也说明了render中的this指向的就是【当前组件】的实例对象(react内部进行了修正) */}
      9. )
      10. }
      11. }
      12. function App () {
      13. return (
      14. "App">
      15. {/* 渲染定义的类组件 */}
      16. )
      17. }
      18. export default App

      建议:在开发中定义函数式组件的时候直接就 handle = () => {} 来定义就行,然后引用的时候直接通过 this.handle来使用,参考count按钮加数操作中的写法。

      react的状态(state)不可变

      目标:能够理解不可变的意义并且知道在实际开发中如何修改状态。

      概念:不能直接修改状态(state)的值,而是基于当前状态创建新的状态值。

      1、错误的直接修改

      1. state = {
      2. count : 0,
      3. list: [1,2,3],
      4. person: {
      5. name:'jack',
      6. age:18
      7. }
      8. }
      9. // 直接修改简单类型Number 这种直接修改状态是不行的
      10. this.state.count++
      11. ++this.state.count
      12. this.state.count += 1
      13. this.state.count = 1
      14. // 直接修改数组 这种直接修改状态是不行的
      15. this.state.list.push(123)
      16. this.state.list.spice(1,1)
      17. // 直接修改对象 这种直接修改状态是不行的
      18. this.state.person.name = 'rose'

      2、 基于当前状态创建新值(正确的修改)

      1. this.setState({
      2. count: this.state.count + 1
      3. list: [...this.state.list, 4], //拿到原有的数据然后再把它赋值给一个新的值
      4. person: {
      5. ...this.state.person,
      6. // 覆盖原来的属性 就可以达到修改对象中属性的目的
      7. name: 'rose'
      8. }
      9. })

      扩展:如何删除数组中的元素? 使用fileter函数

      1. this.setState({
      2. list: this.state.list.filter(item => item !== 2) //把原list中的2给过滤,就是相当于删除了2(这里面还可以写其他过滤条件)
      3. })

      表单处理

      目标: 能够使用受控组件的方式获取文本框的值

      使用React处理表单元素,一般有俩种方式:

      1. 受控组件 (推荐使用)

      2. 非受控组件 (了解)

      什么是受控组件? input框自己的状态被React组件状态控制input框的状态指的就是它的value属性,value是啥它显示的就是啥,同时用户输入的新内容也会被存到这个value值中,所以说input框的状态指的就是这个value属性),react的状态就是我们之前学习的state,所以受控组件指的就是你input的value属性被state中的数据控制了。

      React组件的状态的地方是在state中,input表单元素也有自己的状态是在value中,React将state与表单元素的值(value)绑定到一起,由state的值来控制表单元素的值,从而保证【单一数据源特性】。

      以获取文本框的值为例,受控组件的使用步骤如下:

      1. 在组件的state中声明一个组件的状态数据

      2. 状态数据设置为input标签元素的value属性的值

      3. 为input添加change事件,在事件处理程序中,通过事件对象e获取到当前文本框的值(即用户当前输入的值

      4. 调用setState方法,将文本框的值作为state状态的最新值

      代码实现:

      vue中的v-model数据双向绑定的原理就是下面这么回事:

      1. import React from 'react'
      2. class InputComponent extends React.Component {
      3. // 1、声明组件状态 在状态中声明一个属性用来控制input的value属性
      4. state = {
      5. message: 'this is message',
      6. }
      7. // 声明事件回调函数
      8. changeHandler = (e) => {
      9. //4、拿到输入框的最新值 把它交给state中的message 那么怎么拿到这个value?--->通过e对象
      10. this.setState({ message: e.target.value })
      11. }
      12. render () {
      13. return (
      14. {/* 2、绑定value 绑定事件 把输入框的value属性绑定状态中的属性 3、绑定事件回调函数*/}
      15. )
      16. }
      17. }
      18. function App () {
      19. return (
      20. "App">
      21. )
      22. }
      23. export default App

      下面的内容了解就行:

      非受控组件:就是通过手动操作dom的方式获取文本框的值,文本框的状态不受react组件的state中的状态控制,直接通过原生dom获取输入框的值。

      1. 导入createRef 函数

      2. 调用createRef函数,创建一个ref对象,存储到名为msgRef的实例属性中

      3. 为input添加ref属性,值为msgRef(第二部存储的值的名字)

      4. 在按钮的事件处理程序中,通过msgRef.current即可拿到input对应的dom元素,而其中msgRef.current.value拿到的就是文本框的值(current是固定的属性)

      1. import React, { createRef } from 'react'
      2. class InputComponent extends React.Component {
      3. // 使用createRef产生一个存放dom的对象容器
      4. msgRef = createRef()
      5. changeHandler = () => {
      6. console.log(this.msgRef.current.value)
      7. }
      8. render() {
      9. return (
      10. {/* ref绑定 获取真实dom */}
      11. )
      12. }
      13. }
      14. function App () {
      15. return (
      16. "App">
      17. )
      18. }
      19. export default App

    • 相关阅读:
      标准化、归一化和正则化的关系
      HackTheBox Support 逆向工程获取LDAP凭证,票证伪造提权
      css齿轮转动效果
      1.9 - Cache
      在 Kubernetes 上部署 DM
      java毕业设计计算机组成原理虚拟仿真实验系统mybatis+源码+调试部署+系统+数据库+lw
      NIO Netty(三)
      vue3使用插件fullcalendar生成日历或工作台
      lotus 检索数据 filecoin.tools
      C/C++停车场模拟(栈和队列)
    • 原文地址:https://blog.csdn.net/weixin_53142722/article/details/127680030