React

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

render(
    

hello world!

, document.getElementById('root') )

运行结果如下:
React_第1张图片

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

import React,{ Component } from "react";
import { render } from "react-dom"; 
var flowers = ["玫瑰花","郁金香","百合花"];
render(
    
{ flowers.map((item,index)=>{ return(

我喜欢{item}

) })
} div
>, document.getElementById("root") );

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

var flowers = ["玫瑰花","郁金香","百合花"];
render(
    
{ flowers.map((item,index)=>

我喜欢{item}

)
} div
>, document.getElementById("root") );

两者运行结果都如下:

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

import React,{ Component } from "react";
import { render } from "react-dom"; 
var flowers = ["玫瑰花","郁金香","百合花"];
render(
    
我喜欢{flowers}
, 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 

hello {this.props.name}

} }) render(
"xiao" />, document.getElementById("root") );

另一种写法:

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

class Main extends Component{
    render(){
        return 

hello {this.props.name}

} } render(
"xiao" />, document.getElementById("root") );

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

hello xiao

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

class Main extends Component{
    render(){
        return(
            

hello {this.props.name}

,

喜欢

) } }

上面代码中

<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>
                

hello {this.props.name}

喜欢

div> ) } } render(
"xiao" />, document.getElementById("root") );

运行结果如下:
React_第3张图片
组件类添加属性时要注意,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(
            
    { React.Children.map(this.props.children,function(child){ return (
  • {child}
  • ) }) }
) } } render(
hello world
, document.getElementById("root") );

上面代码组件Main有两个span子节点,它们可以通过this.props.childrend读取,运行结果如下
React_第4张图片
这里需要注意, 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 

{this.props.title}

; } }); var data = 123; ReactDOM.render( , 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 (
            

{this.props.title}

) } } let data = 123; render( , 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 (
            

{this.props.title}

) } } MyComponent.proptypes = { title: React.PropTypes.string.isRequired, } let data = 123; render( , 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 (
            

{this.props.title}

) } } MyComponent.propTypes = { title: PropTypes.string.isRequired, } let data = "123"; render( , 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 (
            

{this.props.title}

) } } MyComponent.defaultProps = { title: "this is flower" } render( , 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 (
            
type="text" ref="myTextInput" /> type="button" value="Focus the text input" onClick={this.handleClick}/>
) } } render( , document.getElementById('root') );

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

Uncaught TypeError: Cannot read property 'refs' of null

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

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

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

"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 (
            

this.handleClick.bind(this)}> You { text } this click toggle

) } } render( , document.getElementById('root') );

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

()=>{this.handleClick()}}> You { text } this click toggle

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

this.handleClick.bind(this)}> You { text } this click toggle

使用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(
            

{this.handleClick()}}> You { text }

) } } render( , 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(
            

()=>{this.handleClick()}}> You { text }

) }

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

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

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

你可能感兴趣的:(react,react)