reactjs前端实践|第三篇:TodoList示例事件、state、props、refs

前端之家收集整理的这篇文章主要介绍了reactjs前端实践|第三篇:TodoList示例事件、state、props、refs前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

实践三

Todo List示例,未使用redux。内容涉及到展示组件与容器组件的合理使用,事件处理,参数传递,控件访问,组件功能设计等方面。其中遇到的坎,设置输入焦点,由于使用了styled-components而有不同;每个组件应试包含哪些state,是否应该进行状态提升;子组件如何向父组件传递数据。

代码分析

组件拆分:Li单个信息条目、LiList信息条目列表、InputAndButton输入组件、App容器组件。App的State包含一个item数组,存放信息列表;InputAndButton的State包含一个inputValue变量,存入用户本次输入的信息。其它组件不含State,为展示组件。

展示组件

Li.js,展示一条信息,数据来自父组件

  1. const Li = (props) => {
  2. return (
  3. <TodoLi>{props.text}</TodoLi> //此处不能加key(但父组件要向它传递),否则会有警告
  4. );
  5. };
  6. export default Li;

LiList.js,展示信息列表,因为输入组件也会修改数据,所以state提升到容器组件中。

  1. const LiList = (props)=>{
  2. return (
  3. <TodoUl>
  4. {props.items.map((item)=>{ //map方法来完成列表构建
  5. return <Li {...item}></Li>; //item中要包含一个key字段,否则会有警告
  6. })}
  7. </TodoUl>
  8. );
  9. };
  10. export default LiList;

输入组件

输入组件自己控制输入框的数据显示及清除,开始我把一切事件处理全放到App中了,这样方便了数据传递,但破坏了输入组件的内聚性。正确的方式是:输入组件自己控制界面的显示,只有在回车键按下或鼠标点击add按钮时,才将输入框中的数据传递给父组件(App)。

InputAndButton.js

  1. class InputAndButton extends Component {
  2. constructor(props) {
  3. super(props);
  4. this.state={
  5. inputValue:'' //用来处理鼠标点击时取得输入数据
  6. };
  7. }
  8. onChange = e => {
  9. this.setState({
  10. inputValue:e.target.value //按键时保存输入数据
  11. })
  12. };
  13. addItem = e => {
  14. if(e.which === 13 || e.type === 'click'){ //回车或鼠标点击
  15. if(this.state.inputValue.trim().length > 0) { //输入不为空
  16. this.props.onSave(this.state.inputValue.trim()); //调用父组件提供的函数,向父组件传递数据。
  17. e.target.value = ''; //清空输入
  18. this.setState({
  19. inputValue:''
  20. })
  21. }
  22. }
  23. };
  24. render = () => {
  25. return (
  26. <div>
  27. <TodoInput onChange={this.onChange}
  28. onKeyUp={this.addItem}
  29. placeholder="enter task"
  30. value={this.state.inputValue}>
  31. </TodoInput>
  32. <TodoButton onClick={this.addItem} type="submit">add</TodoButton>
  33. </div>
  34. );
  35. }
  36. }
  37. export default InputAndButton;

容器组件

  1. class App extends Component {
  2. constructor(props){
  3. super(props);
  4. this.state={
  5. items:[] //信息列表数据
  6. };
  7. }
  8. handleSave(text){ //传递到子组件的函数,接收数据并追加条目
  9. if(text.length !== 0){
  10. this.state.items.push({key: new Date().getTime(),text}); //key设定唯一值,不作说明,网上资料很多
  11. this.setState({
  12. items: this.state.items,})
  13. }
  14. };
  15. render() {
  16. return (
  17. <div>
  18. <InputAndButton onSave={this.handleSave.bind(this)}/> //处理函数以props传给子组件
  19. <LiList items={this.state.items}/>
  20. </div>
  21. );
  22. };
  23. }
  24. export default App;

输入焦点控制

利用特殊的属性 Ref来访问子组件中的控件,并控制输入焦点,需要注意的是:styled-components对这个属性有些改变,要用innerRef来替代ref,不然拿到的是一个 StyledComponent包装的对象,而不是DOM结点。有疑问,去看其文档的Tips and tricks部分之Refs to DOM nodes。

App.js中输入组件修改如下:

  1. <InputAndButton ref={comp => { this.InputComponent = comp; }} onSave={this.handleSave.bind(this)}/>

App.js中增加componentDidMount处理,在组件加载完成时设置输入焦点。

  1. componentDidMount (){
  2. this.InputComponent.focus();
  3. };

InputAndButton.js中修改input如下:

  1. <TodoInput innerRef={el=> { this.el = el; }} ...

InputAndButton.js中增加函数,供父组件中调用

  1. focus = () => {
  2. this.el.focus();
  3. };

项目地址

  1. https://git.oschina.net/zhoutk/reactodo.git
  2. https://github.com/zhoutk/reactodo.git

使用方法

  1. git clone https://git.oschina.net/zhoutk/reactodo.git
  2. or git clone https://github.com/zhoutk/reactodo.git
  3. cd reactodo
  4. npm i
  5. git checkout todo_list_react
  6. npm start

小结

这次实践,学会了事件,数据传递,组件划分,功能设计等基本方法,可以去折腾redux了。

猜你在找的React相关文章