React

1.ReactDOM.render()是react的最基本方法,用于将模板转化为HTML语言,并插入指定的DOM节点。

render(
    <h1>hello world!</h1>,
    document.getElementById('root')
)

运行结果如下:
这里写图片描述

2.JSX语法
上面的代码中,HTML标签直接写在javascript语言中,不加任何引号,这就是JSX的语法,它允许HTML和javascript混写。

import React,{ Component } from "react";
import { render } from "react-dom"; 
var flowers = ["玫瑰花","郁金香","百合花"];
render(
    <div>
        {
            flowers.map((item,index)=>{
                return(
                    <h3 key={index}>我喜欢{item}</h3>
                )
            })  
        }
    </div>,
    document.getElementById("root")
);

上面的代码还有一种写法:

var flowers = ["玫瑰花","郁金香","百合花"];
render(
    <div>
        {
            flowers.map((item,index)=>
                    <h3 key={index}>我喜欢{item}</h3>
            )   
        }
    </div>,
    document.getElementById("root")
);

两者运行结果都如下:

这里写图片描述
但是不建议用后者方法,不容易理解。
上面代码体现了JSX语法格式,遇到<,用HTML规则解析,遇到{,用javascript规则解析。
JSX允许在模板插入javascript变量,如果这个变量是一个数组,会展开所有成员。

import React,{ Component } from "react";
import { render } from "react-dom"; 
var flowers = ["玫瑰花","郁金香","百合花"];
render(
    <div>
        我喜欢{flowers}
    </div>,
    document.getElementById("root")
);

运行结果如下

我喜欢玫瑰花郁金香百合花

那怎么才能让运行结果变成这样呢?

我喜欢玫瑰花,郁金香,百合花

这个问题留给读者
3.组件
react允许将代码封装成一个组件,然后像插入普通HTML标签一样,在网页中插入这个组件,react.createClass()方法用于生成一个组件类。

import React,{ Component } from "react";
import { render } from "react-dom"; 

var Main = React.createClass({
    render: function(){
        return <h1>hello {this.props.name}</h1>
    }
})

render(
    <Main name="xiao" />,
    document.getElementById("root")
);

另一种写法:

import React,{ Component } from "react";
import { render } from "react-dom"; 

class Main extends Component{
    render(){
        return <h1>hello {this.props.name}</h1>
    }
}

render(
    <Main name="xiao" />,
    document.getElementById("root")
);

运行结果都是一样的,如下

hello xiao

上面的代码中变量Main就是一个组件类,模板插入时,会自动生成一个实例,所有组件类都必须有自己的render方法,用于输出组件。
注意:
组件的第一个字母必须大写,否则会报错,比如Main,不能写成main。
另外组件类只能包含一个顶级标签,否则会出现问题。

class Main extends Component{
    render(){
        return(
            <h1>hello {this.props.name}</h1>,
            <p>喜欢</p>
        )
    }
}

上面代码中

<h1>hello {this.props.name}</h1>,
<p>喜欢</p>

用逗号隔开不会报错,但不能正常渲染,渲染的结果如下

喜欢

如果去掉逗号的话,就会报错了

<h1>hello {this.props.name}</h1>
<p>喜欢</p>

报错如下:

Module build failed: SyntaxError: F:/react/redux/react_excise/src/js/index.js: Adjacent JSX elements must be wrapped in an enclosing tag (11:3)

意思就是说相邻的JSX元素必须被包裹在一个封闭的标签
所以正确的写法就是用一个标签包裹起来,正如上面所说组件类只能包含一个顶级标签。
实现代码如下:

class Main extends Component{
    render(){
        return(
            <div>
                <h1>hello {this.props.name}</h1>
                <p>喜欢</p>
            </div>
        )
    }
}

render(
    <Main name="xiao" />,

    document.getElementById("root")
);

运行结果如下:
这里写图片描述
组件类添加属性时要注意,class属性改成className,for属性改成forName。这是因为class和for是javascript标签的保留字。
4、 this.props.children
this.props对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children属性,它表示组件的所有子节点。

import React,{ Component } from "react";
import { render } from "react-dom"; 

class Main extends Component{
    render(){
        return(
            <ul>
                {
                    React.Children.map(this.props.children,function(child){
                        return (
                            <li>{child}</li>
                        )
                    })
                }
            </ul>
        )
    }
}

render(
    <Main>
        <span>hello</span>
        <span>world</span>
    </Main>,
    document.getElementById("root")
);

上面代码组件Main有两个span子节点,它们可以通过this.props.childrend读取,运行结果如下
这里写图片描述
这里需要注意, this.props.children 的值有三种可能:
如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object;
如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。
5.PropTypes
组件的属性可以接受任意值,字符串、对象、函数等等都可以,有时我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的propTypes属性就是验证组件实例的属性是否符合要求。
我们看一下之前是怎么写的

var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});
var data = 123;

ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);

这种写法,是本地引入react.js、react-dom.js和browser.js的写法
这种写法创建组件类通过React.createClass这种方式,但目前这种方法在ES6中已经过时。
我们看下面这种写法:

import React,{ Component } from "react";
import { render } from "react-dom";
import { PropTypes } from "prop-types";

class MyComponent extends Component{
    propTypes: {
        title: React.PropTypes.string.isRequired,
    }
    render(){
        return (
            <h1>{this.props.title}</h1>
        )
    }
}

let data = 123;
render(
  <MyComponent title={data} />,
  document.getElementById('root')
);
import React,{ Component } from "react";
import { render } from "react-dom";

首先我介绍一哈上面这两行代码中的作用,这两行代码是引入react和react-dom,这是ES6的写法,对ES6不熟悉的,可以看阮一峰的ES6,这里就不详细介绍了。

propTypes: {
        title: React.PropTypes.string.isRequired,
    }

其次,上面这段代码是无效的,为什么呢?
因为ES6语法创建组件,其内部只允许定义方法,而不能定义属性,class的属性只能定义在class之外,所以proptypes要写在class组件外
我们看代码是如何实现的:

import React,{ Component } from "react";
import { render } from "react-dom";

class MyComponent extends Component{

    render(){
        return (
            <h1>{this.props.title}</h1>
        )
    }
}
MyComponent.proptypes = {
    title: React.PropTypes.string.isRequired,
}
let data = 123;
render(
  <MyComponent title={data} />,
  document.getElementById('root')
);

但这时报错了,两个警告:

bundle.js:1004 Warning: Failed prop type: Invalid prop `title` of type `number` supplied to `MyComponent`, expected `string`.

这个错误就是我们用PropTypes的目的,因为不是字符串,所以才会报错,如果写成字符串的话,就会消失。

bundle.js:9912 Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.

这个错误的意思就是要安装prop-types,我安装了,但没有用,你可以自己试一下看为什么?在这里不影响我们验证的内容。

真是路漫漫其修远兮啊 这个坑花费了好长时间才踩掉,但我很开心。

经过和室友的研究,最终解决这个上面这个遗留的bug,只需要把React去掉,引进Proptypes。
在引进前需要在命令行中安装

npm install prop-types --save-dev

这是webpack的用法,对webpack不了解的可以看我之前写的webpack教程。
有没有安装成功可以在package.json文件查看

import { PropTypes } from "prop-types";

代码如下:

import React,{ Component } from "react";
import { render } from "react-dom"; 
import { PropTypes } from "prop-types";
class MyComponent extends Component{
    render(){
        return (
            <h1>{this.props.title}</h1>
        )
    }
}
MyComponent.propTypes = {
    title: PropTypes.string.isRequired,
}
let data = "123";
render(
  <MyComponent title={data} />,
  document.getElementById('root')
);

此外,getDefaultProps方法可以用来设置组件属性的默认值。
代码如下:

import React,{ Component } from "react";
import { render } from "react-dom"; 
import { PropTypes } from "prop-types";
class MyComponent extends Component{
    render(){
        return (
            <div>
                <h1>{this.props.title}</h1>
            </div>
        )
    }
}
MyComponent.defaultProps = {
    title: "this is flower"
}
render(
  <MyComponent />,
  document.getElementById('root')
);

上面代码中会输出:

this is flower

6.获取真实的DOM节点
组件并不是真实的DOM,而是存在内存中的一种数据结构,是一种虚拟的DOM,当它真正插入文档中,才会变成真实的DOM。
根据react的设计,所有的DOM变化都先发生在虚拟DOM上,再将实际变动的部分反应在实际的DOM上变化,这种算法叫做DOM diff,它可以提高网页的表现性能。
但是,有时从组件中获取真实DOM节点,这时就用到ref属性。

import React,{ Component } from "react";
import { render } from "react-dom"; 
import { PropTypes } from "prop-types";
class MyComponent extends Component{
    handleClick(){
        this.refs.myTextInput.focus();
        console.log(this.refs.myTextInput.focus());
    }
    render(){
        return (
            <div>
                <input type="text" ref="myTextInput" />
                <input type="button" value="Focus the text input" onClick={this.handleClick}/>
            </div>
        )
    }
}

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

上面这种写法会报错,错误如下:

Uncaught TypeError: Cannot read property 'refs' of null

为什么会报错呢?
因为涉及到this的问题,这里有两种解决方案
一种是:绑定this

<input type="button" value="Focus the text input" onClick={this.handleClick.bind(this)} />

另一种是用箭头函数,会自动绑定this

<input type="button" value="Focus the text input" onClick={()=>{this.handleClick()}} />

在handleClick函数中就可以打印你在输入框中输入的内容。
例如:

xiao

注意:
这里的this指的是组件myComponent,用法可以看30分钟掌握ES6教程
上面的代码中,组件MyComponent的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的DOM,怎么获取呢?
虚拟DOM是拿不到数据的,为了做到这一点,文本输入框必须有一个ref属性,然后this.refs.[refName]就会返回这个真实的DOM节点。

7.this.state
组件免不了和用户互动,React的一大创新,就是将组件看成状态机,一开始有一个初始状态,然后用户互动,导致状态发生变化,从而重新渲染UI。

import React,{ Component } from "react";
import { render } from "react-dom"; 
import { PropTypes } from "prop-types";
class MyComponent extends Component{
    constructor(props){
        super(props);
        this.state = {
            liked: false
        }
    }
    handleClick(event){
        //console.log("aa");
        this.setState({liked: !this.state.liked})
    }
    render(){
        var text = this.state.liked ? 'like': 'haven\'t liked';
        return (
            <p onClick={this.handleClick.bind(this)}>
                You { text } this click toggle
            </p>
        )
    }
}

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

注意:
this的绑定,有三种 方式:
1. var _this = this;
2. bind(this);
3. 箭头函数,它是自动绑定this。
具体需要改动的代码如下:
第一种方式:ES6箭头函数的写法

<p onClick={()=>{this.handleClick()}}>
    You { text } this click toggle
</p>

第二种方式:绑定方式(bind(this))

<p onClick={this.handleClick.bind(this)}>
    You { text } this click toggle
</p>

使用ES6 class语法创建组件,初始化state的工作要在constructor中完成,不需要再调用getInitialState方法。这种语法更加符合JavaScript的习惯。
this.state属性读取,当用户点击组件,导致状态改变,this.setState就修改状态,每次修改以后,自动调用render()方法。再次渲染页面。

在上面整个代码中constructor相当于初始化,执行了一次。

import React,{ Component } from "react";
import { render } from "react-dom"; 
import { PropTypes } from "prop-types";
class MyComponent extends Component{
    constructor(props){
        super(props);
        this.state = {
            liked: false
        }
        console.log("1",this.state.liked)
    }
    handleClick(){
        this.setState({liked: !this.state.liked})
    }
    render(){
        console.log("2",this.state.liked)
        var text = this.state.liked ? 'like' :'no liked';
        return(
            <p onClick={()=>{this.handleClick()}}>
                You { text } 
            </p>
        )
    }
}

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

上面代码我们可以分割出来研究

constructor(props){
        super(props);
        this.state = {
            liked: false
        }
        console.log("1",this.state.liked)
    }

这段代码主要是初始化,所有里面的console执行了一次

render(){
        console.log("2",this.state.liked)
        var text = this.state.liked ? 'like' :'no liked';
        return(
            <p onClick={()=>{this.handleClick()}}>
                You { text } 
            </p>
        )
    }

当点击p标签的内容时,就会执行下面这个函数

handleClick(){
    this.setState({liked: !this.state.liked})
}

每次状态都会取相反的值,第一次默认是false,那么点击一次就会变成true,就会调用render,重新渲染页面。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值