React基础知识点

转自:https://blog.csdn.net/exialym/article/details/52884589

HTML模板

React主要是两个库: 
react.js是核心库 
react-dom.js 是提供与 DOM 相关的功能 
还有一个Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,JSX是可以将HTML直接写在JS里的语言,这一步通常不在浏览器端进行,而是通过babel配合React的babel插件预先转码好。

$ babel src --out-dir build

不过这里我们为了方便就直接将其引入在浏览器端转码。 
于是一个模板就像是这个样子:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Test</title>
  </head>
  <body>

    <script src="../../build/react.js"></script>
    <script src="../../build/react-dom.js"></script>
    <script src="../../build/browser.min.js"></script>
    <script type="text/babel">
      //our React code
    </script>
  </body>
</html>

ReactDOM.render()

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

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('render')
);

JSX 语法

HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法。 
到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。

var names = ['Lion', 'and', 'Rabbit'];
ReactDOM.render(
  <div>
    <div>This is {
      names.reduce((a,b)=>a+' '+b,'')
    }!</div>
  </div>,
  document.getElementById('render2')
);

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员:

var food = [
  <span>福萝卜 </span>,
  <span>牛肉 </span>,
];
ReactDOM.render(
  <div>We like to eat:{food}</div>,
  document.getElementById('render3')
);

这里React会给出一个警告,说Each child in an array or iterator should have a unique “key” prop。 
这个警告和React的Dom diff算法相关。给遍历生成的Dom节点添加key就使得React在生成虚拟Dom树时可以记录下你的操作,在对这部分节点进行实际DOM更新时,通过这个key可以对比原有的节点和新的节点,进行代价最小的插入和删除而不必更新整个Dom组。 
这里的key最好不是数组的下标这类的数据,而是和本Dom节点相关的Unique字符串。最次的选择是下标,那么我们修改一下上面的代码:

var food = [
  <span key='carrot'>福萝卜 </span>,
  <span key='beef'>牛肉 </span>,
];
ReactDOM.render(
  <div>We like to eat:{food}</div>,
  document.getElementById('render3')
);

组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。 
React.createClass 方法就用于生成一个组件类。

//组件类的第一个字母必须大写,否则会报错
      var CookBook = React.createClass({
        render: function() {
          //组件类只能包含一个顶层标签,否则也会报错
          //这里使用一个div作为顶层标签
          //class要写为className,for写为htmlFor,因为JS关键字的原因
          return <div className="CookBookItem">
            <h1>{this.props.name}</h1>
            <div>所需时间:{this.props.time}</div>
            <div>所需食材:{this.props.foods}</div>
          </div>;
        }
      });
      var foods = [
        <span key='tomato'>西红柿、</span>,
        <span key='beef'>牛肉</span>,
      ];
      ReactDOM.render(
        //组件的参数通过HTML属性传进去,在里面使用this.props.xxx获取
        <CookBook name="西红柿牛腩" time="约4个小时" foods={foods}></CookBook>,
        document.getElementById('cookBook1')
      );

this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点。

//组件类的第一个字母必须大写,否则会报错
var CookBook = React.createClass({
  render: function() {
    //组件类只能包含一个顶层标签,否则也会报错
    //这里使用一个div作为顶层标签
    //class要写为className,for写为htmlFor,因为JS关键字的原因
    return <div className="CookBookItem">
      <h1>{this.props.name}</h1>
      <div>所需时间:{this.props.time}</div>
      <div>所需食材:{this.props.foods}</div>
      <ol>
        {
          React.Children.map(this.props.children, function (child) {
            return <li>{child}</li>;
          })
        }
      </ol>
    </div>;
  }
});
var foods = [
  <span key='tomato'>西红柿、</span>,
  <span key='beef'>牛肉</span>,
];
var stepsArr = [
  <div key='wash'>洗菜</div>,
  <div key='cutve'>切菜</div>,
  <div key='cutmeet'>切肉</div>,
  <div key='cook'></div>,
];
ReactDOM.render(
  //组件的参数通过HTML属性传进去,在里面使用this.props.xxx获取
  <CookBook name="西红柿牛腩" time="约4个小时" foods={foods}>{stepsArr}</CookBook>,
  document.getElementById('cookBook1')
);

这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。 
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。

PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。 
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。 
我们在刚才的例子中加入如下代码:

//组件类的这个属性就是用来验证组件实例的属性是否符合要求
propTypes: {
  //这里要求name属性是必须的,且必须为字符串
  name: React.PropTypes.string.isRequired,
},

再添加组件:

ReactDOM.render(
  //name是必须的,所以这里会报错
  <CookBook></CookBook>,
  document.getElementById('cookBook2')
);
ReactDOM.render(
  //name需要是字符串,所以这里会报错
  <CookBook name={123} ></CookBook>,
  document.getElementById('cookBook2')
);

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

//设置默认属性
getDefaultProps : function () {
  return {
    time : '约1小时'
  };
},

获取真实的DOM节点

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。 
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。

var Login = React.createClass({
  //处理点击事件
  //React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、Copy、Scroll 等
  handleClick: function() {
    //虚拟Dom是拿不到用户输入的,使用this.refs.xxx
    //可以获取到真实的Dom节点
    alert(this.refs.username.value)
  },
  render: function() {
    return (
      <div>
        <h1>If You Are Our Friend, Sign In Please.</h1>
        <input type="text" ref="username" />
        <input type="password" ref="password" />
        <input type="button" value="Sign In" onClick={this.handleClick} />
      </div>
    );
  },
  //在组件加载完成时调用
  componentDidMount:function(){
    //焦点放在username上
    this.refs.username.focus();
  }
});

ReactDOM.render(
  <Login />,
  document.getElementById('signUp')
);

this.state

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

var LikeButton = React.createClass({
  //设置初始状态,是一个对象
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    //变更状态
    //只要状态变更,就会调用this.render再次渲染
    //至于是否真的会刷新Dom节点,就要看React使用Dom diff算法的结果了
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    //根据状态渲染节点
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('like')
);

表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props读取,或者你通过刚才的真实Dom节点获取,或者你使用一些事件:

var ContactUs = React.createClass({
  getInitialState: function() {
    return {value: 'name@example.com'};
  },
  handleChange: function(event) {
    //通过事件的target来获取到一个真实的Dom对象就能获取到值了
    //本质上和使用ref是一样的,都是获得真实的Dom节点
    this.setState({value: event.target.value});
  },
  render: function () {
    var value = this.state.value;
    return (
      <div>
        <h3>Leave Your Email</h3>
        <input type="text" value={value} onChange={this.handleChange} />
        <p>{value}</p>
      </div>
    );
  }
})
ReactDOM.render(<ContactUs/>, document.getElementById('contactUs'));

组件的生命周期

组件的生命周期分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

此外,React 还提供两种特殊状态的处理函数。

  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
var Timer = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0,
      time:0,
    };
  },
  //Dom一直在变,于是这个方法总是被调用
  componentDidUpdate(prevProps, prevState) {
    console.log(prevState);
  },
  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      var time = this.state.time;
      time+=100;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity,
        time:time,
      });
    }.bind(this), 100);
  },

  //每100ms重新渲染一次Dom这在以前是开销非常大的
  //但是React的先创建虚拟Dom再更改必要的实际Dom使得这个操作变得非常轻量
  //注意这里的style属性的设置方式
  //React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。
  render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        You have been here for {this.state.time/1000}s
      </div>
    );
  }
});

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

Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI 。

var RepoList = React.createClass({
  //这个组件共有3种状态
  getInitialState: function() {
    return { loading: true, error: null, data: null};
  },

  componentDidMount() {
    //这个组件会传进来一个promise对象
    //在这个promise对象准备好之后会传进组件并触发这个方法
    //设定完成和报错的方法
    //这里在完成或失败之后改变组件的状态,重新渲染组件
    this.props.promise.then(
            value => this.setState({loading: false, data: value}),
            error => this.setState({loading: false, error: error}));
  },
  //render方法根据组件的状态重新渲染组件
  render: function() {
    if (this.state.loading) {
      return <span>Loading...</span>;
    }
    else if (this.state.error !== null) {
      return <span>Error: {this.state.error.message}</span>;
    }
    else {
      var repos = this.state.data.items;
      var repoList = repos.map(function (repo) {
        return (
                <li>
                  <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
                </li>
        );
      });
      return (
              <main>
                <h3>Most Popular JavaScript Projects in Github</h3>
                <ol>{repoList}</ol>
              </main>
      );
    }
  }
});
ReactDOM.render(
        <RepoList
                promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
        />,
        document.getElementById('list')
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值