【阮一峰】React入门实例教程(学习笔记)


一、JSX 语法

  1. 支持Html+JavaScript混写。

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

  3. 在模板中插入数组变量时,要明确key,react的key关乎到react的dom-diff算法。react中对于dom的操作是根据生成的data-reactid进行绑定的,添加key可以保证dom结构的完整性,而不会根据react自己对dom标记的key进行重新分配。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let names = ['Alice', 'Emily', 'Kate'];
    let keyid = 0;

    ReactDOM.render(
    <div
    {
    names.map((name) = {
    return <div key = {keyid++}Hello, { name } !</div
    })
    }
    </div,
    document.getElementById('example')
    );

二、组件

  1. React 版本 16 以前:

    1
    2
    3
    4
    5
    6
    # React.createClass() 用于生成一个组件类
    let HelloMessage = React.createClass({
    render: () = {
    return <h1Hello { this.props.name }</h1
    }
    });
  2. React 版本 16 以后:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class HelloMessage extends React.Component{
    render(){
    return (
    <h1Hello { this.props.name } !</h1
    )
    }
    }
    ReactDOM.render(
    <HelloMessage name="Eva"/,
    document.getElementById("example")
    )
  3. 以上两种的区别:https://www.cnblogs.com/wonyun/p/5930333.html

  4. 所有组件都要有自己的render方法,用于输出组件。

  5. 组件类的第一个字母必须大写,否则会报错。

  6. 组件类只能包含一个顶层标签。

  7. 组件的属性可以在组件类的this.props对象上获取,比如:this.props.name。

  8. 添加组件属性,class属性需要写成className,for属性需要写成htmlFor。这是因为class和for是 JavaScript 的保留字。


三、this.props.children

  1. this.props对象的属性与组件的属性一一对应,但是this.props.children除外

  2. this.props.children表示组件的所有子节点

  3. this.props.children的值有三种可能:

    • undefind —— 没有子节点
    • object —— 只有一个子节点
    • array —— 有多个子节点
  4. 我们可以用 React.Children.map 来遍历子节点


四、PropTypes 组件实例属性验证

  1. 参考

  2. npm安装

    1
    npm install prop-types --save
  3. CDN引用:

    1
    <script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"</script>
  4. 常用数据类型检测

    • 字符串类型PropTypes.string
    • 布尔类型PropTypes.bool
    • 函数类型PropTypes.func
    • 数组类型PropTypes.array
    • 数字类型PropTypes.number
    • 对象类型PropTypes.object
    • 元素PropTypes.element
    • 传入任何东西都可以PropTypes.node
    • 选择特定值PropTypes.oneOf([‘是’, ‘否’, “是否”])
    • 选择诸多类型中的一种(任意类型)PropTypes.oneOfType
  5. 实例:PropTypes静态类型校验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class MyTitle extends React.Component {
    render() {
    return <div{this.props.title}</div;
    }
    }
    MyTitle.propTypes = {
    title: PropTypes.string.isRequired,
    };

    let data = 123;
    ReactDOM.render(
    <MyTitle title={data}/,
    document.getElementById("example")
    )

    // => Warning: Failed prop type: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.
  6. 实例:设置组件属性默认值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class MyTitle extends React.Component {
    render() {
    return <h1{this.props.title}</h1;
    }
    }
    MyTitle.defaultProps = {
    title: 'defaultTitle',
    };

    ReactDOM.render(
    <MyTitle/,
    document.getElementById("example")
    )

五、ref 属性获取真实的DOM节点

  1. 由于this.refs.[refName]属性获取的是真实的DOM节点,所以必须等到虚拟DOM插入文档后才能使用这个属性
  2. 下面实例中,要保证真实DOM发生在事件之后,才能读取到this.refs.[refName]属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class MyComponent extends React.Component{
    handleClick = () = {
    this.refs.myTextInput.focus();
    };
    render = () = {
    return (
    <div
    <input type="text" ref="myTextInput"/
    <input type="button" value="Focus the text input" onClick={this.handleClick}/
    </div
    )
    };
    }

    ReactDOM.render(
    <MyComponent/,
    document.getElementById('example')
    )

六、this.state

  1. 阮一峰教程中使用了getInitialState方法,该方法只能与CreateClass一起使用

  2. 使用React.Component时,需要搭配constructor

  3. this.setState方法不能直接写在constructor中

  4. 只要组件存在constructor,就必须写super,否则this.props将是未定义

  5. 两者的具体区别请对照阮一峰教程和React官方文档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class LikeButton extends React.Component{
    constructor(props) {
    super(props);
    this.state = { liked: false };
    this.handleClick = this.handleClick.bind(this);
    }
    handleClick(){
    this.setState({
    liked: !this.state.liked
    })
    };
    render(){
    let text = this.state.liked ? 'like' : 'have not liked';
    return (
    <p onClick={this.handleClick}
    You {text} this. Click to toggle.
    </p
    )
    }
    }
    ReactDOM.render(
    <LikeButton/,
    document.getElementById('example')
    )

七、表单

  1. 表单需要用户和组件互动,所以不能用this.props直接读取

  2. textarea 元素、select元素、radio元素都属于这种情况

  3. 要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Input extends React.Component{
    constructor(props){
    super(props);
    this.state = {value: "Hello!"};
    this.handleChange = this.handleChange.bind(this);
    }
    handleChange(event){
    this.setState({ value: event.target.value })
    }
    render(){
    let value = this.state.value;
    return (
    <div
    <input type="text" value={ value } onChange={ this.handleChange }/
    <p{ value }</p
    </div
    )
    }
    }
    ReactDOM.render(
    <Input/,
    document.getElementById("example")
    )

八、组件的生命周期

  1. 三种状态

    • Mounting:已插入真实DOM
    • Updating:正在被重新渲染
    • Unmounting:已移出真实DOM
  2. 五种处理函数

    • componentWillMount():在这个函数中,不可以调用setState来修改状态
    • componentDidMount():①.ajax可以再这里调用,返回数据setState后组件会重新渲染;②.可以通过this.refs来访问真实DOM
    • componentWillUpdate(object nextProps, object nextState)
    • componentDidUpdate(object prevProps, object prevState)
    • componentWillUnmount()
  3. 两种特殊状态

    • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用,该函数只监听props的改变,this.setState不会触发这个函数
    • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用,这个函数只返回true或false,表示组件是否需要更新

    转自https://www.cnblogs.com/qiaojie/p/6135180.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class Hello extends React.Component{
    constructor(props){
    super(props);
    this.state = {opacity: 1.0};
    }
    componentDidMount(){
    this.timer = setInterval(function () {
    let opacity = this.state.opacity;
    opacity -= .01;
    if (opacity < 0.1){
    opacity = 1.0
    }
    this.setState({
    opacity: opacity
    })
    }.bind(this), 20)
    }
    render(){
    return (
    <div style={{ opacity: this.state.opacity }}
    Hello { this.props.name }
    </div
    )
    }
    }
    ReactDOM.render(
    <Hello name="world"/,
    document.getElementById('example')
    )

九、Ajax

  1. 我们通常在componentDidMount周期中调用Ajax请求,成功后再用setState方法重新渲染数据
  2. 阮一峰老师的案例中使用的isMouted()方法,在React的ES6语法中已经废弃

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class UserGist extends React.Component{
    constructor(props){
    super(props);
    this.state = {
    username: '',
    lastGistUrl: ''
    }
    }
    componentDidMount(){
    this.serverReq = $.get(this.props.source, function (result) {
    let lastGist = result[1];
    this.setState({
    username: lastGist.owner.login,
    lastGistUrl: lastGist.html_url
    })
    }.bind(this))
    }
    componentWillUnmount() {
    this.serverReq.abort();
    }
    render(){
    return (
    <div
    { this.state.username }'s last gist is <a href={ this.state.lastGistUrl }here</a
    </div
    )
    }
    }
    ReactDOM.render(
    <UserGist source="https://api.github.com/users/octocat/gists"/,
    document.getElementById('example')
    )

    参考文章