ReactJs小书笔记(一)

ReactJs小书笔记(一)

ReactJs小书官方文档:传送门

1 react简介

React.js 不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案。在实际的项目当中,它并不能解决我们所有的问题,需要结合其它的库,例如 Redux、React-router 等来协助提供完整的解决方法。

2 前端组件化(1 2 3 )

<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8">
    <title>Reactjs in 40 </title>
    <style media="screen">
      .like-btn { font-size: 50px; }
    </style>
  </head>

  <body>
    <div class='wrapper'></div>
  </body>

  <script type="text/javascript">
    /* Component */
    class Component {
      constructor (props = {}) {
        this.props = props
      }
      setState (state) {
        const oldEl = this.el
        this.state = state
        this.el = this.renderDOM()
        if (this.onStateChange) this.onStateChange(oldEl, this.el)
      }
      renderDOM () {
        this.el = createDOMFromString(this.render())
        if (this.onClick) {
          this.el.addEventListener('click', this.onClick.bind(this), false)
        }
        return this.el
      }
    }
    const createDOMFromString = (domString) => {
      const div = document.createElement('div')
      div.innerHTML = domString
      return div
    }
    const mount = (component, wrapper) => {
      wrapper.appendChild(component.renderDOM())
      component.onStateChange = (oldEl, newEl) => {
        wrapper.insertBefore(newEl, oldEl)
        wrapper.removeChild(oldEl)
      }
    }
    /* ========================================= */
    class LikeButton extends Component {
      constructor (props) {
        super(props)
        this.state = { isLiked: false }
      }
      onClick () {
        this.setState({
          isLiked: !this.state.isLiked
        })
      }
      render () {
        return `
          <button class='like-btn' style="background-color: ${this.props.bgColor}">
            <span class='like-text'>
              ${this.state.isLiked ? '取消' : '点赞'}
            </span>
            <span>加油的图标</span>
          </button>
        `
      }
    }
    class RedBlueButton extends Component {
      constructor (props) {
        super(props)
        this.state = {
          color: 'red'
        }
      }
      onClick () {
        this.setState({
          color: 'blue'
        })
      }
      render () {
        return `
          <div style='color: ${this.state.color};'>${this.state.color}</div>
        `
      }
    }
    const wrapper = document.querySelector('.wrapper')
    mount(new LikeButton({ bgColor: 'red' }), wrapper)
    mount(new LikeButton(), wrapper)
    mount(new RedBlueButton(), wrapper)
  </script>
</html>

5 React.js 基本环境安装

按照官网的指引安装 create-react-app 即可:

# 安装一条叫 create-react-app 的命令,安装好以后就可以直接使用它来构建一个 react 的前端工程:
$ npm install -g create-react-app
# 构建一个叫 hello-react 的工程,并且会自动地帮助我们安装所需要的依赖,现在只需要安静地等待它安装完
$ create-react-app hello-react
# 进入工程目录然后通过 npm 启动工程:
$ cd hello-react
$ npm start

6 使用 JSX 描述UI信息

  1. 简单的例子:

注意观察各个部分的书写格式;

import React ,{Component} from  'react'
import ReactDOM from 'react-dom'
import './Myindex.css'
//创建Header组件对象
class Header extends Component{
    render(){
        return(
            <div>
                <h1 className= "title">React小书</h1>
            </div>
        );
    }
}
//将JavaScript对象渲染到真实的DOM节点上
ReactDOM.render(
    <Header />,
    document.getElementById('root')
)
  1. JSX 原理,讨论其底层是如何实现的;【JSX 是JavaScript语言的扩展,实际上就是 JavaScript 对象】

用JavaScript对象来表现一个DOM元素结构,每个DOM元素包含的信息有三个:标签名,属性,子元素;

7 组件 render 方法

  1. React.js 中一切皆组件,每一个组件类必须实现一个 render 方法,该方法必须返回一个 JSX 的元素;

注意:只能返回一个外层的标签,返回多个报错;

  1. 表达式插入:JSX中可以插入 JavaScript表达式,表达式必须以 {} 来包裹;

{} 中可以放任何的 JavaScript的代码,包括变量、表达式计算、函数执行等, render 会将这些代码返回的内容渲染到页面上;

  1. JSX 中的样式类使用的是 className ,不是 class;

  2. 条件返回:在 {} 中进行三元操作符的使用,返回结果;

8 组件的组合、嵌套和组件树

  1. 组件的复用性很强,我们可以在组建中调用其他的组件;

注意:自定义的额组件必须以大写字母开头;

//Page组件中调用之前创建的三个小组件
class Page extends Component{
    render(){
        return(
            <div>
                <Header/>
                <Body/>
                <Footer/>
            </div>
        );
    }
}

9 事件监听

  1. 监听用户的动作,我们只需要给需要监听的事件元素加上属性类似于 onClick、 onKeyDown 这样的属性即可;

  2. React.js 封装了不同类型的事件,可以参考学习 SytheticEvent - react

没有经过特殊处理的话,这些 on* 的事件监听只能用在普通的的HTML 的标签上,不能用在组件的标签上;

  1. event 对象:事件监听函数会被自动传入一个 <b>event</b> 对象,该对象与普通浏览器的event 对象所包含的方法和属性均一致,区别是React的 event 对象是内部构建的,并非浏览器所提供;因而,React.js 中,该对象对外提供统一的API 和 属性,而不需要考虑浏览器兼容的问题;
handleClickOnBody(e){
        alert('click on body!');
        //通过 event 对象的e.target.innerHTML对应标签中的内容,并打印
        console.log(e.target.innerHTML);
    }
  1. this 的指向:一般在某个类的实例方法里面的 this 的指向是实例本身,但是在类中的函数里面的this时,会输出为 null 或者 undefined;这是因为React.js 调用方法的时候,不是通过对象的方式调用的函数,而是直接通过函数调用,所以事件监听函数内并不能通过 this 获取到实例;若要在事件函数中使用当前的实例,需要手动将实例方法 bind 到当前的实例上再传入React.js ;或者用ES6 最新语法箭头函数也可以解决该问题;
render(){
        return(
            <div onClick= {this.handleClickOnBody.bind(this)}>
                <h2>React body 部分</h2>
            </div>
        );
    }

//箭头函数写法,解决this的指向,或者是调用时加入bind(this)
    handleClickOnBody=(e)=>{...}

10 组件的state 和setState

  1. React中的state是用于存储组件的状态;

一个组件的显示形态可以由它的数据状态和配置参数决定;

  1. setState方法: 接收对象或者是函数作为参数

setState 方法由父类 Component 提供,当我们调用这个函数时,React.js 会更新组件的状态 state ,并且重新调用 render 函数,将最新的状态渲染到页面上去;例:

class Likebutton extends Component{
    //构造器中初始化state状态
    constructor(){
        super();
        this.state={ 
            isLiked:false,
            count:0 
        }
    }
    //点击按钮触发状态改变
    handleClickOnLikeButton(){
        //接收对象作为参数
        this.setState({
            isLiked: !this.state.isLiked
        })
        //接收函数作为参数
        const preveState= this.state;
        this.setState((preveState)=>{
            return{count: preveState.count +10};//count 数值加 10
        })
    }
    //渲染页面
    render(){
        return(
            <div>
                <p>是否点赞?</p>
                <button onClick= {this.handleClickOnLikeButton.bind(this)}>
                    {this.state.isLiked? '取消' : '点赞'}
                </button>
                <p>count:{this.state.count}</p>
            </div>
        );
    }
}

11 配置组件的 props

  1. render 函数中可以看出,组件内部是通过 this.props 的方式获取到组建的参数的,若 this.props 里面有需要的属性就采用,没有则采用默认属性;
//创建Likebutton2组件对象
class Likebutton2 extends Component{
    //通过static静态变量设置默认的props,取代后面的 || 的设置
    static defaultProps= {
        liketest: '取消',
        unliketest: '点赞'
    }
    //构造器中初始化state状态
    constructor(){
        super();
        this.state={ isLiked:false,count:0 }
    }
    //点击按钮触发状态改变
    handleClickOnLikeButton(){
        //接收对象作为参数
        this.setState({
            isLiked: !this.state.isLiked
        })
    }
    //渲染页面
    render(){
        const liketest= this.props.liketest || '取消';
        const unliketest= this.props.unliketest || '点赞';
        return(
            <div>
                <p>Likebutton2</p>
                <button onClick= {this.handleClickOnLikeButton.bind(this)}>
                    {this.state.isLiked? liketest : unliketest}
                </button>
            </div>
        );
    }
========================================================
    //在另一个大的组组件中设置 Likebutton2 的props属性
    render(){
        return(
            <div>
                <Header/>
                <Body/>
                <Footer/>
                <Likebutton/>
                <Likebutton2 liketest= '已赞' unliketest= '赞'/>
            </div>
        );
    }
  1. 设置默认的 defaultProps,代码建上方示例代码中;

  2. props 不可变原则:React.js 希望一个组件在输入在输入确定的 props 时,能够输出确定的UI显示状态,因而渲染过程中props不可修改;组件使用者可以主动的通过重新渲染的方式把新的props 传入组件中,组件的显示形态将得到变化;

12 state VS props

  1. state :让组件控制自己的状态

主要作用是用于组件保存、控制、修改自己的可变状态;state在组建的内部初始化,可以被组件自身修改,而外部不能访问也不能修改;可以认为state是一个局部的、是能被组件自身控制的数据源;state状态通过this.setState 方法进行更新,setState会导致组件重新渲染;

  1. props :让外部对组件进行配置

主要作用是让使用该组件的父组件可以通过传入桉树来配置该组件;它是外部传进来的配置参数,组件内部五大控制修改;只有当外部主动传入新的 props 后,组件的props 才会改变;

  1. 无状态组件:不加人状态以及props属性

  2. 函数式组件与继承 Component 来构建组件的区别:
    函数式组件只接受props,不接受在constructor里面初始化state,函数式组件就是只能接受props 和提供render方法的类组件;

函数式组件示例代码:

//函数式组件的创建
const HelloWorld= (props)=>{
    const sayHi= (event)=> alert('Hello world!');
    return(
        <div onClick= {sayHi}>helloworld 点我看看</div>
    );
}

13 渲染列表数据

  1. 若把数组放入 {} 中,React.js 会把 {} 数组里面的每个元素罗列并渲染出来;

  2. 使用 map 渲染列表数据

//数据源users
const users = [
    { username: 'Jerry', age: 21, gender: 'male' },
    { username: 'Tomy', age: 22, gender: 'male' },
    { username: 'Lily', age: 19, gender: 'female' },
    { username: 'Lucy', age: 20, gender: 'female' }
];
//使用map函数遍历数据源Datalist
class Datalist2 extends Component{
    render(){
        return(
        <div>
            {users.map((user)=>{
                return(
                <div key={user.username}>
                    <div> 姓名:{user.username}</div>
                    <div> 年龄:{user.age}</div>
                    <div> 性别:{user.gender}</div>
                    <hr/>
                </div> 
                )
            })}
        </div>);
    }
}

14 实战分析:评论功能(1)

  1. 组件划分:React.js 中一切皆是组件,当我们拿到了一个需求后,首先应该理解需求、分析需求、划分这个需求由哪些组件构成;

划分组件的目的是为了代码的可复用性和可维护性;

  1. 该评论功能的组件划分:整个大组件为 CommentApp ,包含 CommentInput 组件和 CommentList 组件,其中 CommentList 组件中包含多个单个的 Comment 评论条小组件;

  2. 组件的实现:

先利用 create-react-app 构建一个新的工程,cmd中执行: create-react-app react-comment-app

再在 src 目录下建立上述的四个文件:CommentApp.js、CommentInput.js、CommentList.js和Comment.js,再实现一个最基本的组件嵌套的功能,对整个大组价加入一定的样式显示;

15 实战分析:评论功能(2)

  1. 处理用户输入:CommentInput.js 文件

加入HTML 的框架,包括用户名、用户名的输入框、评论内容、输入的内容区和提交的按钮;

  1. 数据处理逻辑:

加入构造器函数 constructor ,里面填写 state 状态初始化数据,包含用户名输入框和评论内容,分别设置为空字符:this.state= {username:'', content:''}

  1. 用户输入框、内容区分别设置其 value 属性为 {this.state.username}{this.state.content},以备后面的大组价CommentApp通过props属性获取CommentInput组件中输入的用户名以及内容数据,实现父组件CommentApp获取到子组件CommentInput的数据,如下代码所示:

注意此处书写的代码的巧妙之处,不同于之前利用props属性将数据从父组件传递到子组件,此处为逆向传递数据;

/* 父组件CommentApp中 */
//构造器初始化state状态,设置初始保存的内容数组为空
    constructor(){
        super();
        this.state= {
            comments:[]
        }
    }
    //handleSubmitContent函数获取子组件CommentInput的输入内容
    handleSubmitContent(comment){
        // console.log(comment);
        if(!comment) return
        if(!comment.username) return alert('请输入用户名')
        if(!comment.content) return alert('请输入评论内容')
        this.state.comments.push(comment);
        this.setState({
            comments:this.state.comments
        });
    }
    //渲染到页面
    render(){
        return (
            <div className= "wrapper">
                {/* <p>hello React</p> */}
                <CommentInput onSubmit= {this.handleSubmitContent.bind(this)}/>
                <CommentList comments= {this.state.comments}/>
            </div>
        );
    }

/* ============================================== */

/* 子组件CommentInput中 */

//handleSubmit函数点击发布按钮触发内容提交
    handleSubmit(){
        if (this.props.onSubmit){
            const {username, content}= this.state;
            this.props.onSubmit({username, content});
        }
        this.setState({
            content: ''
        });
    }

16 实战分析:评论功能(3)

  1. 数据显示组件 CommentList.js

先尝试模拟一组用户加内容的数组数据,先实现这个组件对数据的显示功能;通过 map 函数实现对于数组数据中的对象取值(render 函数中),如下代码所示:

    return(
        <div >
            {this.props.comments.map((comment, i)=> <Comment comment= {comment} key= {i}/> )}
        </div>
    );
  1. 单个显示的组件 Comment.js

先设计这个组件返回的HTML的框架,设置相应的样式;

数据信息则是通过 props 属性获取父组件中的内容数据对象,分别将用户名和内容信息解析到不同的地方,如下代码所示:

{this.props.comment.username}

{this.props.comment.content}
  1. 在去掉模拟数据源,通过获取用户的提交数据作为数据源

数据显示组件 CommentList 是通过props 属性从父组件 CommentApp 中获取的数据,如下代码所示:

{this.props.comments.map((comment, i)=> <Comment comment= {comment} key= {i}/> )}
  1. 测试显示map 报错,是由于map遍历的comments数组为用户输入数据,当用户还没有输入数据时,为空,则会报错;防止这个错误产生,我们可以通过static静态方法设置默认的props属性,设置其内的comments为一个空数组对象;
static defaultProps={
  comments:[]
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350