时隔一年, 再次入门, 这次是真的用react做点项目了.

缘起, 为啥react?
  • react入门摸不到头脑. 照旧前端的几座大山一路过来.
    • 官网, react的官网还真不错, 至少有这一篇: 为啥我们造react.
    • wikipedia
    • mdn
    • Stack Overflow
    • 知乎, 最近我发现知乎的水准也已经很不错了, 可以和上面的大贤看起.
  • 我们逐个看看他们是怎么说的:
wikipedia
  • 有介绍, 有案例.
官网
  • https://reactjs.org/blog/2013/06/05/why-react.html
  • 对应的翻译: https://blog.csdn.net/XIAOZHUXMEN/article/details/51460016
  • http://react-china.org/t/topic/1560
  • http://react-china.org/t/topic/1560
  • react是一个包,
  • 官网就有中文, 太神奇了: https://zh-hans.reactjs.org
    • 开始的介绍页: https://zh-hans.reactjs.org/docs/getting-started.html
    • 入门的一个动手教程: https://zh-hans.reactjs.org/tutorial/tutorial.html
    • helloworld这样的整体教程: https://zh-hans.reactjs.org/docs/hello-world.html
    • react哲学: https://zh-hans.reactjs.org/docs/thinking-in-react.html
知乎
  • 各种话题. 有个叫[方正]的, 写的都比较干货. 不过都偏深入了一些, 不合适用来入门.
其他
  • 国内有个阮一峰, 写的还不错, 但是, 真心地官网更透彻.
结论
  • 跟着官网入门没毛病: https://zh-hans.reactjs.org/docs/getting-started.html
过程一: 官网的tutorial
  • 根据官网做了一遍: https://zh-hans.reactjs.org/tutorial/tutorial.html
  • 做完之后有点晕, 概念有点多, 再回顾一遍.
    • component, 组件
    • props, 组件的参数, 可以直接用标签属性传递.
    • render会返回react element元素, react元素是一个js 对象
    • state可以用来保留组件的私有属性. setState调用时会引起子组件更新.
    • constructtor构造函数.
    • DOM 元素 <button> 是一个内置组件,因此其 onClick 属性在 React 中有特殊的含义.
    • 而react自定义的组件, onclick是我们任意命名的. 中间有一段详细的解释了整个调用链.

最关键的调用链关系

每一个 Square 被点击时,Board 提供的 onClick 函数就会触发。我们回顾一下这是怎么实现的:
1. 向 DOM 内置元素 <button> 添加 onClick prop,让 React 开启对点击事件的监听。
2. 当 button 被点击时,React 会调用 Square 组件的 render() 方法中的 onClick 事件处理函数。
3. 事件处理函数触发了传入其中的 this.props.onClick() 方法。这个方法是由 Board 传递给 Square 的。
4. 由于 Board 把 onClick={() => this.handleClick(i)} 传递给了 Square,所以当 Square 中的事件处理函数触发时,其实就是触发的 Board 当中的 this.handleClick(i) 方法。
5. 现在我们还尚未定义 handleClick() 方法,所以代码还不能正常工作。如果此时点击 Square,你会在屏幕上看到红色的错误提示,提示内容为:“this.handleClick is not a function”。

这一段下面的黄色段落也是很关键的内容, 解释了内置组件和自定义组件在事件响应上的重大不同. 这个不同非常关键.

疑问:

<Board squares={current.squares} onClick={(i)=>this.handleClick(i)}/> 
//这里这个i啥时候传进去的? 这个onclick是一个属性会传递到子组件里面, 子组件可以用props.onclick来引用这个属性.
//因此board的这里引用了这个函数:
renderSquare(i) {
    return <Square value={this.props.squares[i]} onClick={()=> this.props.onClick(i)} />; //这个i就是上面的参数.
}

过程二: 官网的hello world
  • 这个教程的步骤更细一些, 比较容易理解.

  • react元素

    • jsx啥都能当, 变量, 参数等等都可以.
    • 元素element组成组件component.
    • reactdom.render把元素插入节点, 类似codemirror的做法.
    • react元素是不可变对象
    • react元素可以是dom标签也可以是用户自定义组件.
  • 组件

    • 单个参数的函数就是最简单的react组件, 他的返回值返回react元素.
    • 用class定义react.component组件, 和上面的简单的函数形式本质上是等价的.
    • 组件可以任意的组合组件.
  • state

    • state和props类似, 不论父组件还是子组件都不关心本组件是否有状态, 除了拥有state的组件, 外部无法直接访问某个组件的state, 因此说state是私有的. 但是, state可以作为props向下传递到子组件之中.
    • setstate方法可以更新state, 同时触发界面更新. 也就是触发组件的render方法.
    • 三个注意事项
      • 不要直接修改state, 而是使用setstate.
      • state和props都可能是异步更新的. 因此无法正常依赖props和state, 因为要用的时候这两个可能就都更新了, 因此, 要做出依赖, 就不用对象作为setstate的参数, 而是用函数作为参数. 函数里面把state和props作为参数传进去, 然后这个函数返回值是个对象.
      • setstate只更新传进去的键值对.
  • react有一些声明周期方法:

    • constructor, 这里可以声明state.
    • componentDidMount
    • componentWillUnmount
  • react事件

    • react事件是小驼峰
    • react事件返回false不能阻止默认行为, 必须preventdefault.
    • 事件传递多个参数
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
    //这两种方式中, event事件对象都是第二个参数.
    
    • 关于this
    //正常的写法, this会不存在:
    class LoggingButton extends React.Component {
      
      handleClick() {
        console.log('this is:', this);
      }
      
      render() {
        return (
          <button onClick={this.handleClick}>
            Click me
          </button>
        );
      }
    }
    //这个语法虽然this正确, 但是每次rander时都会创建新的函数.
    <button onClick={(e) => this.handleClick(e)} />
    //这个写法类似传统的函数写法, 但是不同于正常的react组件方法, 是个实验性写法.
    handleClick = () => {
      console.log('this is:', this);
    }
    //在构造函数中用bind也能保证this存在
    constructor(props) {
      super(props);
      this.state = {isToggleOn: true};
      
      // 为了在回调中使用 `this`,这个绑定是必不可少的
      this.handleClick = this.handleClick.bind(this);
    }
    
  • 列表需要有key, key的目标是更新的时候能提升效率, 因此, 把不会变的串作为key更合理.

    • 有一个经验的做法是, 在map发生的地方设置key.
    • key属性本身就是给react用的, 并不会传递到组件的props, 因此如果需要这个key, 请用其他属性名传递.
  • 组件的值

    • 受控组件: 组件的值只由state控制.
      • textarea: 也是value作为值.
      • select: 也是用value指明选择的条.
      • 受控组件的value如果设置为undefine或者null, 那么就意味着值可以直接编辑.
    • 非受控组件:
      • file input, 这个不能受控了.

特别注意

  • 组件名必须大写开头,比如Square, 小写开头的都会被认为是原生dom元素, 比如div.
  • 所有的react组件必须都类似纯函数, 也就是不能去修改入参. 例如props都是不能修改的.
  • 状态提升这一章卡了我一下, 内容比较多, 貌似=tutorial的自己动手教程. 核心点: 数据流自上而下, 不要做组件之间的同步, 而是做上层组件向下传递.
  • 如果数据可以推导出来, 那么就不应该保存在state中.
  • 不要使用继承
    • 界面元素使用组装方式搞.
    • 非ui功能用模块搞, 然后import.
helloworld的第12章非常特殊, 值得单独来讲: React 哲学
  1. 用数据结构推导页面结构.
  2. 先做静态页面, 再做交互.
    1. 静态版本不需要state, 只需要props.
    2. 简单的项目适合顶向下, 大型项目用底向上方式更合适(我没碰到过).
  3. 确定state最简.
    1. 如果是从父组件传下来, 那么就不是state, 仅仅是props.
    2. 如果保持不变, 那么也不是state.
    3. 如果能够根据其他state和props计算出来, 那么也不是state.
  4. 确定state放置的位置.
    1. 所有需要这个state来做渲染的组件.
    2. 找到他们的共同拥有者.
    3. 如果没有唯一的共同拥有者, 那么就建一个.
  5. 反向数据流.
    1. 其实是通过事件绑定走的.
    2. 逐个往上传递, 通过props绑定的事件.
数据传递用props和state
  • setState是异步的. 所以state不会立刻更新.
  • state值要想正常使用, 最好再构造函数做个初始化.

感触: 如果是使用封装好的控件, props几乎废了, 只能用state或者下面这种

<Button shape="circle" onClick={_ => this.handlepot('outputdata')} ghost>
  <Icon type="share-alt" />
</Button>

state方式:

<TextArea
  rows={4}
  style=
  value={this.state.outputdata}
  onChange={this.handleoutputChange}
  />
react实际上把数据和界面做了绑定
  • 大家的值都依赖state, state更新的时候, 值是自动更新的.
  • 界面上面的动作, click, change等等会引起state的更新, 然后又会反过来刷新state