zoukankan      html  css  js  c++  java
  • The Road to learn React书籍学习笔记(第二章)

    
    

    The Road to learn React书籍学习笔记(第二章)

    组件的内部状态

    组件的内部状态也称为局部状态,允许保存、修改和删除在组件内部的属性,使用ES6类组件可以在构造函数中初始化组件的状态。构造函数只会在组件初始化的时候调用一次

    类构造函数

    1 class App extends Component{
    2   constructor(props){
    3     super(props);
    4   }
    5 }

    使用ES6编写的组件有一个构造函数时,需要强制地使用 super() 方法, 因为这个 App组件Component 的子类,因为需要在 App组件 声明 extends Component 也可以调用 super(props),它会在构造函数中设置 this.props 以供构造函数中访问。否则在构造函数中访问 this.props ,会得到 undefined

    例子,组件的初始状态是一个列表

     1 const list = [
     2  {
     3   title:'React',
     4   url: 'https://facebook.github.io/react/',
     5   author: 'Jordan Walke',
     6   num_comments: 3,
     7   points: 4,
     8   objectID: 0,
     9  }
    10 ];
    11 12 class App extends Component{
    13   constructor(props){
    14     super(props);
    15     this.state = {
    16       list : list,
    17     }
    18   }
    19 }

    state 通过使用 this 绑定在类上,因此可以在整个组件中访问到 state。通过 render() 方法可以映射一个在组件外定义静态列表

     1 class App extends Component{
     2   render(){
     3     return(
     4       <div className = "App">
     5         {this.state.list.map(item =>
     6           <div key = {item.objectID}>
     7             <span><a href = {item.url}>{item.title}</a></span>
     8             <span>{item.author}</span>
     9             <span>{item.num_comments}</span>
    10             <span>{item.points}</span>
    11           </div>
    12           )
    13         }
    14       </div>
    15     );
    16   }
    17 }

    现在list是㢟的一部分,它在组件的 state 中,可以从list添加、修改、删除列表项。组件的 render 会再次运行,可以简单修改组件内部状态,确保组件重新渲染并且展示从内部状态获取到的正确数据 修改 state 可以使用 setState() 方法来修改

    ES6 对象初始化

    初始化例子

    1 const name = 'Laibh';
    2 const user = {
    3   name : name
    4 };

    当对象中属性名与变量名相同时可以如下操作

    1 const name = 'Laibh'; 
    2 const user = {
    3   name
    4 };

    在应用程序中,列表变量名与状态属性名称共享同一名称

    1 //ES5 
    2 this.state = {
    3   list:list
    4 }
    5 6 //ES6
    7 this.state = {
    8   list
    9 };

    简写方法名

     1 //ES5
     2 var userService = {
     3   getUserName :function(user){
     4     return user.firstname + ' ' + user.lastname;
     5   }
     6 }
     7  8 //ES6
     9 const userService = {
    10   getUserName(user){
    11     return user.firstname + ' ' + user.lastname;
    12   }
    13 }

    计算属性名

     1 //ES5
     2 var user = {
     3   name:'Laibh'
     4 }
     5  6 //ES6
     7 const key = 'name';
     8 const user = {
     9   [key] :'Laibh'
    10 }

    单向数据流

    组件中有一些内部的 state,练习 state 操作的好方式增加一些组件的互动 为列表增加一个删除按钮

     1   class App extends Component {
     2  3   render() {
     4     return (
     5       <div className="App">
     6         {this.state.list.map(item =>
     7           <div key={item.objectID}>
     8             <span>
     9               <a href={item.url}>{item.title}</a>
    10             </span>
    11             <span>{item.author}</span>
    12             <span>{item.num_comments}</span>
    13             <span>{item.points}</span>
    14             <span>
    15               <button
    16                 onClick={() => this.onDismiss(item.objectID)}
    17                 type="button"
    18               >
    19                 Dismiss
    20               </button>
    21             </span>
    22           </div>
    23         )}
    24       </div>
    25     );
    26   }
    27 }

    上面类中,onDismiss() 还没有被定义,它通过id来标识哪个应该被删除,此函数绑定到类,就成为了类方法,所以访问它的时候要用 this.onDismiss() 而不是用 onDismiss()this 对象是类的实例,为了将 onDismiss() 定义为类方法,需要在构造函数中绑定它。并定义它的逻辑功能

     1   class App extends Component {
     2  3   constructor(props) {
     4     super(props);
     5  6     this.state = {
     7       list,
     8     };
     9 10     this.onDismiss = this.onDismiss.bind(this);
    11   }
    12    onDismiss(id) {
    13   ...
    14   }
    15 16   render() {
    17     ...
    18   }
    19 }

    可以使用JavaScript内置的 filter 方法来删除列表的一项,它会遍历整个列表,通过条件来过滤,匹配的返回 true 并留在列表中

    1 onDismiss(id){
    2   const updateList = this.state.list.filter(function isNotId(item){
    3       return item.objectID !== id
    4     });
    5 }

    或者一行箭头函数

    1 onDismiss(id){
    2   const updateList = this.state.list.filter(item => item.objectID !== id);
    3 }

    接着要更新数据

    this.setState({list:updateList});

    绑定

    类不会自动绑定 this 到实例上 需要自己绑定

    1 constructor() {
    2     super();
    3 4     this.onClickMe = this.onClickMe.bind(this);
    5   }

    类的绑定方法也有人写在其他地方,例如render()函数中

    1 render(){
    2   return(
    3     <button onClick = {this.onClickMe.bind(this)}>Click Me</button>
    4   )
    5 }

    但是应该避免这样使用,因为它会在每次 render() 方法执行的时绑定类方法。组件每次更新都会导致性能消耗,当在构造函数中绑定的时候,绑定只会在组件实例化时运行一次,这样是一个更好的方式

    另外有一些人剔除在构造函数中定义业务逻辑类方法

    1 constructor(){
    2   super();
    3   this.onClick = () =>{
    4     conlose.log(this);
    5   }
    6 }

    这样随着时间推移会让构造函数变得混乱,避免使用。构造函数的目的只是实例化类以及所有的属性

    事件处理

    1 <button
    2   onClick={() => this.onDismiss(item.objectID)}
    3   type="button">
    4   Dismiss
    5 </button>

    当传递一个参数到类的方法,需要将它封装到另一个(箭头)函数中,由于要传递给事件处理器使用,因为它必须是一个函数,而下面的这个代码不会工作。因为类方法会在浏览器中打开程序时候立即执行

    1 <button onClick = {this.onDismiss(item.objectID)}>
    2     Dismiss
    3 </button>

    倘若写成

    1 <button onClick = {onDismiss}>
    2     Dismiss
    3 </button>

    就不会立即执行,但是需要传参数,所以就不这么用

    另外的一个解决方案是在外部定义一个包装函数,并且只将定义的函数传递给处理程序。因为需要访问特定的列表项,所以它必须位于 map 函数块的内部

     1 class App extends Component{
     2   render(){
     3     return(
     4       <div className = "App">
     5         {this.state.list.map(item =>
     6           const onHandldDismiss = () =>
     7             this.onDismiss(item.objectID);
     8  9             return(
    10               <div key={item.objectID}>
    11                 <span>
    12                   <a href={item.url}>{item.title}</a>
    13                 </span>
    14                 <span>{item.author}</span>
    15                 <span>{item.num_comments}</span>
    16                 <span>{item.points}</span>
    17                 <span>
    18                   <button
    19                     onClick={onHandleDismiss}
    20                     type="button"
    21                   >
    22                     Dismiss
    23                   </button>
    24                 </span>
    25               </div>
    26             )
    27         )}
    28       </div>
    29     )
    30   }
    31 }

    在事件处理程序中使用箭头函数对性能会有影响

    和表单互动

     1 const list = [{
     2   title: 'React',
     3   url: 'https://facebook.github.io/react',
     4   author: 'Jordan Walke',
     5   num_comments: 3,
     6   points: 4,
     7   objectID: 0,
     8 }, {
     9   title: 'Redux',
    10   url: 'https://github.com/reactjs/redux',
    11   author: 'Dan Abramov, Andrew Clark',
    12   num_comments: 2,
    13   points: 5,
    14   objectID: 1,  
    15 }];
    16 const isSearched = searchText => item => item.title.toLowerCase().includes(searchText.toLowerCase());
    17 class FormP extends Component{
    18   constructor(props){
    19     super(props);
    20     this.state = {list,searchText:''};
    21     this.onSearchChange = this.onSearchChange.bind(this);
    22     this.onDismiss = this.onDismiss.bind(this);
    23   }
    24   onSearchChange(e){
    25     this.setState({searchText:e.target.value});
    26   }
    27   onDismiss(id){
    28     console.log(this);
    29     const updateList = this.state.list.filter(item =>
    30       item.objectID !== id
    31     );
    32     this.setState({list:updateList});
    33   }
    34   render(){
    35     return(
    36       <div className = "FormP">
    37         <form>
    38           <input type="text" onChange = {this.onSearchChange}/>
    39         </form>
    40         {this.state.list.filter(isSearched(this.state.searchText)).map(
    41           item =>
    42           <div key = {item.objectID}>
    43           <span>
    44             <a href= {item.url}>{item.title}</a>
    45           </span>
    46           <span>{item.author}</span>
    47           <span>{item.num_comments}</span>
    48           <span>{item.points}</span>
    49           <span>
    50             <button onClick = {()=>this.onDismiss(item.objectID)}>Dismiss</button>
    51           </span>
    52         </div>  
    53         )}
    54       </div>
    55     )
    56   }
    57 }
    58 59 export default FormP;

    ES6 解构

    在JavaScript ES6 中有一个更方便的方法来访问对象和数组的属性,叫做解构。

     1   const user = {
     2     firsname : 'L',
     3     lastname : 'binhong'
     4   }
     5  6   //ES5
     7   var firstname = user.firstname;
     8   var lastname = user.lastname;
     9 10   console.log(firstname + '' +lastname);
    11 12   //ES6
    13   const {firstname, lastname} = user;
    14   conlose.log(firstname + '' +lastname);

    在JavaScript ES5中每次访问对象的属性都需要额外添加一行代码,但是ES6中就可以在一行中进行,可读性最好的方法就是将对象解构成多个属性时使用多行 对于数组也可以使用解构,可以保持代码的可读性

    1 const user = ['1','2','3'];
    2 const [
    3   a,
    4   b,
    5   c
    6 ] = user;
    7 8 console.log(a,b,c); //1,2,3

    受控组件

    表单元素 <input>/<select>/<textarea> 会以元素HTML的形式保存它们自己的状态,一旦有人从外部做了修改,就会修改内部的值,在React中这被称为不受控组件,因为它们自己处理状态,在React中,我们得把它们变成 受控元素

     1   class App extends Componet{
     2     render(){
     3       const {searchText,list} = this.state;
     4       return(
     5         <div className = "App">
     6           <form>
     7             <input
     8               type = "text"
     9               value = {searchText}
    10               onChange = {this.onSearchChange}
    11             ></input>
    12           </form>
    13         </div>
    14       )
    15     }
    16   }

    现在输入框的单项数据流循环是自包含的,组件内部状态是输入框的唯一数据来源

    拆分组件

    用于搜索的输入组件和一个用于展示的列表组件

     1   class App extends Componet{
     2     render(){
     3       const {searchText,list} = this.state;
     4       return(
     5         <div className = "App">
     6           <Search />
     7           <Table />
     8         </div>
     9       )
    10     }
    11   }

    在组件传递属性并在组件中使用,App组件需要传递本地状态 state 托管的属性和它自己的类方法

     1   class App extends Component{
     2     render(){
     3       const {searchText,list} = this.state;
     4       return(
     5         <div>
     6           <Search 
     7             value = {searchText}
     8             onChange = {this.onSearchChange} />
     9           <Table 
    10             list = {list}
    11             pattern = {searchText}
    12             onDismiss = {this.onDismiss} />
    13         </div>
    14       )
    15     }
    16   }

    Search组件

     1   class Search extends Component{
     2     render(){
     3       const {value,onChange} = this.props;
     4       return(
     5         <form>
     6           <input
     7             type = "text"
     8             value = {value}
     9             onChange = {onChange} />
    10         </form>
    11       )
    12     }
    13   }

    Table组件

     1   class Table extends Component{
     2     render(){
     3       const {list,pattern.onDismiss} = this.props;
     4       return(
     5         <div>
     6           {list.filter(isSearched(pattern)).map(item =>
     7             <div key = {item.objectID}>
     8               <span><a href = {item.url}>{item.title}</a></span>
     9               <span>{item.title}</span>
    10               <soan>{item.points}</span>
    11               <span>{item.num_comments}</span>
    12               <button onClick ={() => onDismiss(item.objectID)}>
    13                 Dismiss
    14               </button>
    15             </div>
    16           )}
    17         </div>
    18       )
    19     }
    20   }

    可组合组件

    props 对象中还有一个小小的属性可以供使用: children 属性.通过这个属性可以将元素从上层传递到组件中,这些元素对组件来说是未知的,但是却为组件互相结合提供了可能性、 下例中,将一个文本作为子元素传递到Search组件中

     1   class App extends Component{
     2     render(){
     3       const {searchText,list} = user;
     4       return(
     5         <div>
     6           <Search 
     7             value = {searchText}
     8             onChange = {this.onSearchChange} />
     9       )
    10     }
    11   }

    Search 组件可以从 props 对象中解构出 children 属性,就可以指定它应该在哪里显示

     1 class Search extends Component{
     2   render(){
     3     const {value,onChange,children} = this.props;
     4     return(
     5       <form>
     6         {children}
     7         <input
     8           type = "text"
     9           value = {value}
    10           onChange = {onChange} />
    11       }
    12       </form>
    13     )
    14   }
    15 }

    可复用组件

    可复用和可组合组件帮助理解合理的组件分层,它们是React视图层的基础

     1   class Button extends Component{
     2     render(){
     3       const {onClick,className,children} = this.props;
     4       return(
     5         <button 
     6           onClick = {onClick}
     7           className = {className}
     8           type = "button">
     9           {children}
    10         </button>
    11       )
    12     }
    13   }

    Button组件拥有单一可信数据源,一个Button组件可以立即重构所有button。一个Button组件统治了所有button

    <Button onclick = {() => onDismiss(item.objectID)}>Dissmiss</Button>

    函数式无状态组件(function stateless componenet)

    这类组件就是函数,它们接受一个输入并返回一个输出。输入时props,输出就是一个普通的JSX组件实例。函数式无状态组件是函数,并且它们没有本地状态。不能通过 this.state 或者是 this.setState() 来访问或者更新状态,因为这里没有 this 对象,此外,它也没有生命周期方法。 constructor()render() 就是其中两个。 constructor 在一个组件的生命周期只执行一次,而 render() 方法只会在最开始执行一次

    ES6 类组件

    在类的定义中,它们继承自 React 组件。 extend 会注册所有的生命周期方法,只要在 React component API中,都可以在组件中使用。通过这种方式,可以使用 render() 方法,此外还可以通过使用 this.statethis.setState() 来存储和操作 state

    把上例的Search组件重构为一个函数式无状态组件

     1 function Search(props){
     2   const {value,onChange,children} = props;
     3   return{
     4     <form>
     5       {children}<input
     6         type = "text"
     7         value = {value}
     8         onChange = {onChange} />
     9     </form>
    10   }
    11 }

    或者将参数放在函数里面

     1 function Search({value,onChange,children}){
     2   return{
     3     <form>
     4       {children}<input
     5         type = "text"
     6         value = {value}
     7         onChange = {onChange} />
     8     </form>
     9   }
    10 }

    然后ES6 箭头函数一波

    1 const Search = ({value,onChange,children}) =>
    2   <form>
    3     {children}<input
    4       type = "text"
    5       value = {value}
    6       onChange = {onChange} />
    7   </form>  

    如果想在ES6箭头函数写法中做些事情的话 可以这样写

     1 const Search = ({value,onChange,children}) => {
     2  3   //do something
     4   return(
     5     <form>
     6       {children}<input
     7         type = "text"
     8         value = {value}
     9         onChange = {onChange} />
    10     </form>
    11   )
    12 }

    给组件声明样式

    可以复用 src/App.css 或者 src/index.css 文件

  • 相关阅读:
    编程浪子我的个人知识树
    JAVA基本数据类型
    JS导出数据为表格-csv
    table表格打印样式
    ENTER键指定事件
    legend生成表单边框效果
    js按拼音排序算法
    CommonJs规范
    iscroll在安卓高版本(6.0以上)某些机型上滑动卡顿问题的解决方法
    前端常见报错原因详解
  • 原文地址:https://www.cnblogs.com/lbh2018/p/theroadtolearnreactpart2.html
Copyright © 2011-2022 走看看