React---基础2(List/Key、表单(ref、event)、状态提升(共享组件)、组件占位符)

七、列表 和 键

  列表(List), 键(Key)
  回顾一下在javascript中如何转换列表:在数组中使用map()函数对numbers数组中的每个元素依次执操作

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled)  // 2, 4, 6, 8, 10

  React 基本借鉴了以上写法,只不过将数组替换成了元素列表

多组件渲染

  可以创建元素集合,并用一对大括号 {} 在 JSX 中直接将其引用即可

  下面,我们用 JavaScript 的 map() 函数将 numbers 数组循环处理。对于每一项,我们返回一个

  • 元素。最终,我们将结果元素数组分配给 listItems

    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((number) => 
        
  • {number}
  • )

    再把整个 listItems 数组包含到一个

      元素,并渲染到DOM
       

      ReactDOM.render(
          
        {listItems}
      , document.getElementById('root') )

      基本列表组件

        通常情况下,我们会在一个组件中渲染列表而不是直接放到root上。重构一下上例

      function NumberList(props) {
          const numbers = props.number;
          const listItems = numbers.map((number) => 
              
    • {number}
    • ) return (
        {listItems}
      ) } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( , document.getElementById('root') )

        当运行上述代码的时候,将会受到一个警告:a key should be provided for list items,要求应该为元素提供一个键(注:min版本react无提示)。要去掉这个警告也简单,只需要在listItem的每个li中增加key属性即可,增加后的每个

    • 如下

      function NumberList(props) {
        const numbers = props.numbers;
        const listItems = numbers.map((number) =>
          
    • {number}
    • ); return (
        {listItems}
      ); }

        当创建元素列表时,“key” 是一个你需要包含的特殊字符串属性,那为什么要包含呢?

      键(Keys)

        键Keys 帮助React标识那个项被修改、添加或者移除了。数组中的每一个元素都应该有一个唯一不变的键来标识。

       挑选key最好的办法是使用一个在它的同辈元素中不重复的表示字符串。多数情况下可以使用数据中的IDs来作为Keys。但是还是会遇到没有id字段的数据,这种情况你可以使用数据项的索引值

      cosnt todoItems = todos.map((todo, index) => 
          // 数据项没有IDs时使用该办法
          
    • {todo.text}
    • )

        如果列表项可能被重新排序,这种用法存在一定的性能问题,React会产生时间复杂度为O(n^3)的算法执行。因此优先使用数据项本身的字段内容来设置键

      使用 Keys 提取组件

      Keys只有在数组的上下文中存在意义。例如,如果你提取了一个ListItem组件,应该把key放置在数组处理的元素中,而不能放在ListItem组件自身的

    • 根元素上。

       以下的用法就是错误的

      function ListItem(props) {
          const value = props.value;
          return (
              // 错误!不需要再这里指定 key
              
    • {value}
    • ) } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 错误!key 应该在这里指定: ); return (
        {listItems}
      ); }

        应该写成如下

      function ListItem(props) {
        // 正确!这里不需要指定 key :
        return 
    • {props.value}
    • ; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 正确!key 应该在这里被指定 ); return (
        {listItems}
      ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( , document.getElementById('root') );

      keys 在同辈元素中必须唯一

        在数组中使用的 keys 必须在它们的同辈之间唯一。然而它们并不需要全局唯一。我们可以在操作两个不同数组的时候使用相同的 keys :

      function Blog(props) {
        const sidebar = (
          
        {props.posts.map((post) =>
      • {post.title}
      • )}
      ); const content = props.posts.map((post) =>

      {post.title}

      {post.content}

      ); return (
      {sidebar}
      {content}
      ); } const posts = [ {id: 1, title: 'Hello World', content: 'Welcome to learning React!'}, {id: 2, title: 'Installation', content: 'You can install React from npm.'} ]; ReactDOM.render( , document.getElementById('root') );

        【注意】键是一个内部映射,他不会作为props传递给组件内部,如果你需要在组件中使用到这个值,可以自定义一个属性名将该值传入到props中,如下例中我们定义了一个id属性传入给props.

      const content = posts.map((post) =>
        
      );
      

        在这个例子中,我们能读取props.id,但是读取不了props.key

      直接在JSX中使用map()

        在上例中我们先声明了一个listItem然后在jsx中引用,然而我们也能在JSX中直接引用,称之为 内联map()

      function NumberList(props) {
        const numbers = props.numbers;
        return (
          
        { numbers.map((number) => )}
      ); }

        至于选用哪种风格编写,只要遵循代码清晰易读原则即可。

      八、表单

      refs

      refs:标识组件内元素(相当于document.getElementById,获取DOM元素)

       DOM操作官方说明

      要求:自定义组件,并完成以下功能

      • 点击按钮,提示第一个输入框的值
      • 第二个输入框失去焦点,提示输入值
      // 1.定义组件
      class MyComponent extends React.Components {
          // 1.1 强制绑定(给自定义方法的this强制绑定为组件对象)
          constructor(props) {
              super(props)
              this.showInput = this.showInput.bind(this)
              this.showOutBlur = this.showOutBlur.bind(this)
      
          }
          // 1.2 自定义方法
          showInput() {
              const input = this.refs.input
              alert(input.value)
          }
          showOutBlur(event) {
              alert(event.target.value)
          }
          // 1.3 渲染
          render() {
              return (
                  
      ) } }

      获取表单数据

      • 受控组件
      • 非受控组件

      1、非受控组件

      ref={input => this.nameInput=input},前一个input是形参,可以自定义,和最后的input一致;nameInput也是自定义

      2、受控组件
      在组件中: 

      
      

      在方法中:

      handleChange(event) {
      	const psw = event.target.value
      	this.setState({ psw: psw })
      }
      

      完整代码:

      /

      HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素自然地保留了一些内部状态。例如,这个纯 HTML 表单接受一个单独的 name:

        该表单和 HTML 表单的默认行为一致,当用户提交此表单时浏览器会打开一个新页面。如果你希望 React 中保持这个行为,也可以工作。但是多数情况下,用一个处理表单提交并访问用户输入到表单中的数据的 JavaScript 函数也很方便。实现这一点的标准方法是使用一种称为“受控组件(controlled components)”的技术。

      受控组件(Controlled Components)

        在 HTML 中,表单元素如

        在 React 中,