react入门系列之使用create-react-app搭建一个todolist-dome

安装create-react-app脚手架

  • npm install -g create-react-app

创建你的todo-list项目

  • create-react-app todo-list

  • 注意npm命名限制,项目名称不能含有大写字母。

清除项目中不必要的文件

  • src目录中的:App.css, App.test.js, logo.svg, serviceWorker.js文件

  • public目录中的: manifest.json文件

  • 其中manifest.json,serviceWorker.js属于pwa的配置文件,有兴趣可以了解一下。

  • pwa 让网页写好以后,用户访问了一次之后,就可以把我们的网页当作app来用,可以不用联网。

  • 在手机上或者电脑桌面上通过点击快捷方式来打开页面。

  • 他的图标和快捷方式是通过public中manifest.json去定义的

之前删除的文件在剩下的文件有引入使用,现在将其删除

  • App.js删除下列代码注释部分

import React, { Component }from 'react';

// import logo from './logo.svg';

// import './App.css';

class App extends Component {

  render(){

    return (

      {

        /*

      <div className="App">

        <header className="App-header">

          <img src={logo} className="App-logo" alt="logo" />

          <p>

            Edit <code>src/App.js</code> and save to reload.

          </p>

          <a

            className="App-link"

            href="https://reactjs.org"

            target="_blank"

            rel="noopener noreferrer"

          >

            Learn React

          </a>

        </header>

      </div>

      */

      }

      <div>

      hello react

      </div>



    );

  }

}

export default App;

  • index.js 删除一下注释部分

import React from 'react';

import ReactDOM from 'react-dom';

// import './index.css';

import App from './App';

//import * as serviceWorker from './serviceWorker'; // pwa 引入

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change

// unregister() to register() below. Note this comes with some pitfalls.

// Learn more about service workers: https://bit.ly/CRA-PWA

// serviceWorker.unregister(); // pwa 使用

  • public中的index.html文件,删除以下注释部分代码

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="utf-8" />

    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />

    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <meta name="theme-color" content="#000000" />

    <meta

      name="description"

      content="Web site created using create-react-app"

    />

    <link rel="apple-touch-icon" href="logo192.png" />

    <!--

      manifest.json provides metadata used when your web app is installed on a

      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/

    -->

    <!--

      <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

    -->

    <!--

      Notice the use of %PUBLIC_URL% in the tags above.

      It will be replaced with the URL of the `public` folder during the build.

      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will

      work correctly both with client-side routing and a non-root public URL.

      Learn how to configure a non-root public URL by running `npm run build`.

    -->

    <title>todo-list</title> <!-- 更改网页标题 -->

  </head>

  <body>

    <noscript>You need to enable JavaScript to run this app.</noscript>

    <div id="root"></div>

    <!--

      This HTML file is a template.

      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.

      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.

      To create a production bundle, use `npm run build` or `yarn build`.

    -->

  </body>

</html>

项目目录解析

  • yarn.lock -- 包锁文件

  • README.MD -- 项目介绍

  • package.json -- node的包文件

  • .gitignore -- 使用git的时候可以将不想上传到git的文件在此处标记

  • node_modules -- 项目依赖包

  • index.html 项目首页模版

  • favicon.ico 网页图标

  • index.js 入口js文件

  • app.js 万年老二组件

jsx语法

  • jsx语法规定,在return中的最外层只能含有一个标签。

  • 为此你可以使用div也可以使用react提供的Fragment占位符,他其实也是一个组件。

  • 在js中写html标签。就称为jsx语法

  • render()函数中return => html标签或者组件名加括号,组件必须以大写字母开头

  • jsx中使用变量,需要使用{}包裹

  • 现在我们将App.js改造成如下代码。

  • 通过npm run start 启动你的项目


    import React, { Component, Fragment } from 'react';

    class App extends Component {

      render(){

        return (

          <Fragment>

            <div >

            <input/><button>提交</button>

            </div>

            <ul>

              <li>react</li>

            </ul>

          </Fragment>

        );

      }

    }

export default App;

react的响应式思想和事件绑定

定义数据

  • 之前我们已经将todo-list的结构搭好了。现在需要实现功能。

  • 不要直接操作dom

  • 通过改变数据改变dom

  • 此时我们需要准备两组数据,1组数据存储input里面的值,1组数据存储列表中的值。

  • 如何定义数据?

    • 一个类必定有一个构造函数,并且他是最先执行的函数,我们可以将数据存在这个构造函数中

    • constructor 即为App类的构造函数,构造函数中有state属性,他是用来存放这个类的变量的。

    • 因此数据就定义在state中。

    • constructor 构造函数还有一个super()方法,他可以帮助App类调用他的父类(Component)的属性。

  • 使用箭头函数不然this指向出错

  • 只能通过setState方法去改变state中的变量

  • 代码如下


    import React, { Component, Fragment }from 'react';

    class App extends Component {

      constructor(props){

        super(props);

        this.state = {

          inputValue: '',// 用来存储 input框中的 value值。

          list:[] // 用来存储 每一个li的 value值。

        }

      }

      render(){

        return (

          <Fragment>

          <div>

            <input/>

            <button>提交</button>

          </div>

          <ul>

            <li>react</li>

          </ul>

          </Fragment>

        );

      }

    }

    export default App;

绑定数据

  • 我们上面已经定义好了数据,现在将数据绑定到对应的dom上

  • 这样方便我们通过数据改变dom

  • react jsx语法中,绑定数据到dom上,使用{} 包裹。 -- value = {this.state.inputValue}

  • 列表数据绑定也是一样,在{}中写js表达式,我们可以通过es5的map函数遍历list数组获得item值,和他的下标

  • 然后通过return返回一个li标签,返回之前,将item绑定到li的value值,将index作为li的key

  • 注意的是,实际开发中将index作为key值是一个错误的做法。


    import React, { Component, Fragment }from 'react';

    class App extends Component {

      constructor(props){

        super(props);

        this.state = {

          inputValue: '',// 用来存储 input框中的 value值。

          list:['西瓜','苹果'] // 用来存储 每一个li的 value值。

        }

      }

      render(){

        return (

          <Fragment>

          <div>

            <input value = {this.state.inputValue} />

            <button>提交</button>

          </div>

          <ul>

            {

              this.state.list.map((item, index) => {

                return (

                  <li key={index}>

                    {item}

                  </li>

                )

              })

            }

          </ul>

          </Fragment>

        );

      }

    }

    export default App;

react的事件绑定

  • 我们现在需要绑定input的onChange事件,以此达到input的value值的变化和我们数据inputValue变化一致

  • react的事件绑定和原生的区别就是第二个单词首字母要大写,onChang

  • 在onChange事件中绑定handleInputChange()方法,传入事件对象,获取target值,他的value就是当前input的value值

  • 再通过this.setState()方法区改变组件中inputValue的值。

  • 要注意的是,react中只能通过setState方法改变state中的属性。


      import React, { Component, Fragment }from 'react';

    class App extends Component {

      constructor(props){

        super(props);

        this.state = {

          inputValue: '',// 用来存储 input框中的 value值。

          list:['西瓜','苹果'] // 用来存储 每一个li的 value值。

        }

      }

      handleInputChange = (e) => {

        this.setState({

          inputValue: e.target.value

        })

        console.log(e.target)

      }

      render(){

        return (

          <Fragment>

          <div>

            <input

            onChange = {this.handleInputChange}

            value = {this.state.inputValue} />

            <button>提交</button>

          </div>

          <ul>

            {

              this.state.list.map((item, index) => {

                return (

                  <li key={index}>

                    {item}

                  </li>

                )

              })

            }

          </ul>

          </Fragment>

        );

      }

    }

    export default App;

如何实现Todolis的增删功能

  • 增加思路 在input框中输入要添加的字段,点击提交,提交绑定一个方法,将inputValue的值添加到list数组中

  • 删除思路 在每一个li中绑定点击事件,在点击的时候,传入当前li的下标,在事件方法中通过下标删除list中的对应元素

  • 要注意的时,在传入index的时候我尝试过直接在方法名后面传入,但是会报错,改在bind()方法中第二个参数传入,就没有问题了

  • state中的属性数据,只能通过this.setState({})方法修改,不能直接修改。

  • 在使用splice的时候踩了一个坑,list = list.splice(index, 1)

  • 这是一行错误代码,这样赋值,list等于是你删除的哪个元素组成的数组,splice会改变原数组,返回被删除的数组。无需再赋值


    import React, { Component, Fragment } from 'react';

    class App extends Component {

      // 定义数据,一个类必定有一个构造函数,他是最先执行的函数

      constructor(props){

        super(props); // App继承Component类,所以要通过super(props)调用他的父类的属性

        this.state = {

          inputValue: '', // input框的value

          list: [] // 列表的数据

        }

      }

      handleInputChange = (e) => { // 使用箭头函数不然this指向出错

        this.setState({ // 只能通过setState去改变state中的变量

          inputValue : e.target.value

        })

        console.log(e.target)

      }

      // 增加方法

      handleBtnClick = () => {

        this.setState({

          list : [...this.state.list, this.state.inputValue],

          inputValue: ''

        })

      }

      // 删除方法

      handleItemDelet = (index) => {

        console.log(index)

        let list = [...this.state.list];

        // list = list.splice(index, 1) // 这是一行错误代码,这样赋值,list等于是你删除的哪个元素组成的数组

        list.splice(index, 1)

        console.log(list)

        this.setState({

          list : [...list]

        })

      }

      render(){

        return (

          <Fragment>

            <div >

            <input

            value = { this.state.inputValue } // 数据相应绑定

            onChange = { this.handleInputChange } // 事件绑定

            />

            <button

            onClick = { this.handleBtnClick }

            >提交</button>

            </div>

            <ul>

              {

              this.state.list.map((item, index) => {

                return <li key={index} onClick = { this.handleItemDelet.bind(this, index) }>{item}</li>    // 实际编程之中使用index做key值是一个非常不好的习惯

              })

              }

            </ul>

          </Fragment>

        );

      }

    }

export default App;

jsx细节补充

  • 注释用大括号包裹,单行注释要换行

  • 添加样式使用 className ,class会被解析成类

  • dangerouslySetInnerHTML = {js表达式}

  • dangerouslySetInnerHTML = {{ __html: item }} 多一个花括号表示一个js对象

  • // 如果需要显示input框中内容中的标签效果 就这么写。但是这样写容易造成xss攻击 对应的标签中就不需要写item了

  • lable标签 使用htmlFor引入到指定标签中


  render(){

    return (

      <Fragment>{/* 他其实是一个组件 */ }

        <div >

        <lable htmlFor = "insertArea">输入内容</lable>

        <input

        id = 'insertArea'

        className = 'input'

        value = { this.state.inputValue } // 数据相应绑定

        onChange = { this.handleInputChange } // 事件绑定

        />

        <button

        onClick = { this.handleBtnClick }

        >提交</button>

        </div>

        <ul>

          {

          this.state.list.map((item, index) => {

            return (

            <li

            key={index}

            onClick = { this.handleItemDelet.bind(this, index) }

            dangerouslySetInnerHTML = {{ __html: item }} // 如果需要显示input框中内容中的标签效果 就这么写。但是这样写容易造成xss攻击

            >



            </li>) // 实际编程之中使用index做key值是一个非常不好的习惯

          })

          }

        </ul>

      </Fragment>

    );

  }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容