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