react学习总结2--基础(二)

react 学习总结–基础(二)

说明

React 版本 :”15.4.1”

react-tap-event-plugin 版本: “^2.0.1”

1.数据流

在 React 中,数据流的流向是单向的–从父节点传递到子节点,因而组件是简单且易于把握的,他们只需从父节点获取props渲染即可

React 组件内部还具有自己的状态,这些状态只能在组件内修改,React组件本身很简单,可以把它看成是一个函数,他接受 props 和 state 作为参数,返回一个虚拟DOM表现

Props(属性)

props 就是 properties 的缩写,你可以使用它把任意类型的数据传递给组件。可以在挂在组件的时候设置它的props

    let obj = {name : 'aaa', age : 20 };
    <Child obj={obj} />

通过组件实例的setProps方法(很少这样做)来设置props

    let obj = {name : 'aaa', age : 20};
    let myChild = ReactDOM.render(
      <Child />,
      document.getElementById('app')
    );
    myChild.setProps({name : 'bbb'});

注:在组件内,props只能由父组件传递进来,子组件内不能修改自己的 props ,即不能通过this.setProps,或者this.props直接修改props

props的格式,可以设置为字符串,<a href="/home"></a>
也可以使用{},注入JavaScript传递任意类型的变量 <a href={'/home/' + this.state.id}></a> ,添加事件处理 <a onClick={this.handleClick}></a> 也可以使用展开语法 <Child {...props} />

State(状态)

React 将组件看成一个状态机,有一个初始状态,然后随着与用户的互动,导致状态变化,从而触发重新渲染UI 每一个React组件都可以拥有自己的state,组件的state只存在于组件内部

state可以通过setState来修改,也可以通过getInitialState方法提供一组默认值,只要setState被调用,render方法就会被调用,如果render返回值有变化,虚拟DOM就会更新

注:不能使用this.state.name = 'name'这样的方式修改state,只能通过this.setState({name : 'name'})这种方式修改

    class Test extends Component {
    constructor(props) {
        super(props);
        this.state = {
          num : 0
        };
    }
    componentDidMount() {
      this.setState({num : 2});
    }
    render() {
        return (
            <Child childNum={this.state.num} />
        );
    }
}
PropTypes(props验证)

组件的属性可以是任意值,但有时候我们需要验证别人使用组件的时候,提供的参数是否符合要求,PropsTypes属性,就是React提供的验证传入props的有效性的方式
当向props传入无效数据时,JavaScript控制台会抛出警告

为了性能考虑,只在开发环境验证propsTypes

    class Modal extends Component {
        static propTypes = {
            children: PropTypes.node, //表示这些 props 是可传可不传的
            isOpen: PropTypes.bool.isRequired, //表示这些 props 不可以为空
        }
        ...
    }

这里有更详细的验证器

2.事件处理

React 事件处理本质上跟JavaScript事件一样,命名上与JavaScript一致,并且会在相同的情景下触发,React标准化了事件对象,使用驼峰式命名 <input type="button" onClick={this.handleClick.bind(this)}>,显式的调用bind(this),将函数上下文绑定到组件实例上。

事件捕获处理

一般写法onClick={this.handleClick.bind(this)}会在事件冒泡阶段触发,如果想在事件捕获阶段触发需要加上Capture,例如 onClickCapture={this.handleCaptureClick.bind(this)}

虚拟事件对象

React 的事件对象event是经过封装的,没有浏览器兼容问题,他有和浏览器本地事件相同的属性和方法
但是如果需要调用底层的浏览器事件对象,只需要使用nativeEvent属性就可以获取,
常用的属性和方法如下

  • stopPropagation() 阻止事件冒泡
  • preventDefault() 阻止默认事件
  • target 触发事件的对象
  • currentTarget 绑定事件的对象
  • nativeEvent 原生浏览器事件对象
  • type 事件类型

更多请见虚拟事件对象

触摸事件

旧版本的 React 为了使触摸事件生效,需要在渲染所有组件之前调用React.initializeTouchEvents(true)
但是在新版本的 React 中已经停用,要使用触摸事件需要引入react-tap-event-plugin,然后在渲染所有组件之前,调用injectTapEventPlugin();

为避免300ms之后再次触发onClick(也就是点击一次,反应两次)可以进行配置

    injectTapEventPlugin({
      shouldRejectClick: function (lastTouchEventTimestamp, clickEventTimestamp) {
        return true;
      }
    });

更多详情请看react-tap-event-plugin

3.复合组件

本质上,一个组件就是一个JavaScript函数,它接受props和state两个参数,并输出渲染好的HTML,组件一般被用于呈现和表达应用的某部分数据

我们可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离

    class ChildBtn extends Component{
      constructor(props) {
          super(props);
      }
      render() {
          return <button>点击</button>;
      }
    }
    class ChildInput extends Component{
      constructor(props) {
          super(props);
      }
      render() {
          return <input type="text" />;
      }
    }
    class Test extends Component {
        constructor(props) {
            super(props);
        }
        render() {
            return (
               <div>
                 <ChildInput />
                 <ChildBtn />
               </div>
            );
        }
    }
子级

<Parent><Child /></Parent>

如上,Child 就是 Parent 的子级,在Parent中能通过this.props.children读取子级

4.Mixin

mixin允许我们定义可以再多个组件中共用的方法,它们就是混合近组件中的对象而已,React的Mixin
能够防止静默函数覆盖,同时支持多个Mixin混合

React.createClass({
    mixins : [{
        getInitialState: function(){return {a : 1}}
    }],
    getInitialState: function(){return {b : 2}}
});
//最终结果:state => {a:1,b:2}
ES6 写法

如果要使用ES6编写React组件,不建议使用Mixins机制,将会使用高阶组件代替代Mixins,更多详情请看
高阶组件替代Mixins

5.DOM操作

多数情况下,React的虚拟DOM足以用来创建你想要的用户体验,但是有些情况下不得不操作底层的DOM,例如:使用第三方类库,或者执行一个React没有原生支持的操作,为了是这些操作变得容易,React提供了一个可以用于处理受其自身控制的DOM节点的方法,这些方法在组件生命周期的特定阶段才能被访问到

ref属性

ref属性,用来配合获取真实的DOM节点,下边是一个例子

    class Test extends Component {
        constructor(props) {
            super(props);
            this.state = {
              value : ''
            }
        }
        handleClick(){
            let textInput = ReactDOM.findDOMNode(this.refs.text);
            console.log(textInput); // 获取到真实DOM元素
        }
        handleChange(e){
          this.setState({value : e.target.value});
        }
        render() {
            return (
               <div>
                <input type="text" 
                  ref="text"
                  value={this.state.value}
                  onChange={this.handleChange.bind(this)}
                />
                <button onClick={this.handleClick.bind(this)}>获取输入内容</button>
               </div>
            );
        }
    }

访问到相应的DOM节点,需要通过this.refs.[refName]找到相应的子组件,定义ref,必须保障赋给每个子组件的ref值在所有的子组件中是唯一的,找到子组件后,通过ReactDOM.findDOMNode()方法访问到底层的DOM节点

注意:只有在组件被挂载后才能访问,在有些生命周期中可以访问到,但获取的DOM不是最新的,以下是其执行环境

  • componentDidMount
  • componentDidUpdate
  • 事件处理函数中(事件处理函数都是在组件挂载后触发)

注:旧版本会用this.refs.text.getDOMNode()的方式获取,新版本中已经不能使用,替换为ReactDOM.findDOMNode(this.refs.text)

注:有其他方式能够实现功能时,尽量不要使用此功能,在性能上会有一定障碍,同时增加了组件的复杂性

6.表单

表单组件不同于其他组件,因为他们可以通过用户交互发生变化
表单组件支持几个受用户交互影响的属性

  • value,用于 <input><textarea> 组件。
  • checked,用于类型为 checkbox 或者 radio<input> 组件。
  • selected,用于 <option> 组件。
无约束组件

即表单组件的值是不受React控制的,在React中,这种行为与设置<input /> 的 defaultValue一致
我们可以通过设置defaultValue属性设置默认值

    class MyForm extends Component{
      render() {
        return (
          <input type="text" defaultValue="hello" /> 
        );
      }
    }

这个例子展示的就是无约束组件,组件的value并非由父组件设置,而是让<input />自己控制自己的值

约束组件

也就是表单组件的状态交由React组件控制,状态值被存储到React组件的state中

    class MyForm extends Component{
      constructor(props){
        super(props);
        this.state = {
          value
        };
      }
      handleChange(e){
        this.setState({value : e.target.value})
      }
      render() {
        return (
          <input type="text" 
            value={this.state.value} 
            onChange={this.handleChange.bind(this)} 
          /> 
        );
      }
    }

<input />的值存储在父组件的state中

文本框和select

React 对<textarea /><select/>做了一些修改,提升了一致性

    <textarea name="description" value="This is a description." />
    <select value={this.state.value} onChange={this.handleChange.bind(this)}>
        <option value="A">fir</option>
        <option value="B">sec</option>
        <option value="C">thr</option>
    </select>
单选框和复选框
    class Test extends Component{
      constructor(props){
        super(props);
        this.state = {
          checked : false
        };
      }
      handleChange(e){
        this.setState({checked : e.target.checked})
      }
      render() {
        return (
          <input type="checkbox" 
            checked={this.state.checked} 
            onChange={this.handleChange.bind(this)} 
          /> 
        );
      }
    }

7.会用到的API

ReactDOM.unmountComponentAtNode

ReactDOM.unmountComponentAtNode(DOMElement containe)销毁指定容器内的所有React节点。

  ReactDOM.unmountComponentAtNode(document.getElementById('app'));

注:只能销毁ReactDOM.render(<app />,document.getElementById('app')) 中的容器内部节点,通过react产生的节点使用此方法回报错:

  ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this.refs.remove));
  warning.js:36 Warning: unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component.
React.isValidElement

React.isValidElement(object)判断一个对象是否是一个ReactElement(不是很常用)

  let c = <Test />;
  console.log(React.isValidElement(c));//true

只有在判断的对象是实例化的react组件时,才会返回true

React.cloneElement()

React.cloneElement()克隆并返回一个新的 ReactElement (内部子元素也会跟着克隆),新返回的元素会保留有旧元素的 props、ref、key。可以传入三个参数
1.要克隆的ReactElement;2.需要新添加的属性props;3.重新设置的子节点(会替换掉原本的子节点)

  render() {
    let span = <span ref="span">aaa</span>;
    let spanChange = React.cloneElement(span, {name:'aaa'} ,<em>bbb</em>);
    return (
      <div>
        {spanChange}
      </div>
    );
  }             
  //结果:<span name="aaa"><em>bbb</em><span>
React 遍历

React.Children.map()可以实现遍历,但是我一般直接用map

  render() {
    let arr = ['A','B','C','D'];
    return (
      <div>
        <ul>
          {
            arr.map((item,i) => {
              return (<li key={i}>{item}</li>)
            })
          }
        </ul>
      </div>
    );
  }

注意:像这样循环添加react节点的操作一定要加上key属性,否则会有警告:

warning.js:36Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method ofTest. See https://fb.me/react-warning-keys for more information.

forceUpdate

forceUpdate() 就是重新运行render,有些变量不在state上,但是又想达到变量更新,重新render的效果的时候,就可以使用此方法手动触发render

  handleClick(){
    this.forceUpdate(function () {
      console.log('update'); //render之后的回调
    });
  }
一些使用es6就不能使用的API
  • replaceState
  • isMounted
  • Mixin

下一篇–React-Router传送门

  • API,及常用方法
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值