列表和关键字

作者: 编码的哲哲 | 来源:发表于2017-02-16 17:44 被阅读36次

    首先,让我们回顾一下你是如何用javascript来转换一个列表。在下面的代码中,我们用map函数来使得一个数字数组中的数加倍并且将它打印到控制台:

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

    上面这段代码将在控制台打印出[2,4,6,8,10],在react中将数组转化为列表的方法和上面的方法类似。

    渲染多个组件

    你可以创建一个element的集合并把它们包裹在打括号中,下面的代码用map函数将数组中的数字全部转换成li元素,最后将它保存到listItems数组中:

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

    我们将listItems数组中的元素插入到ul节点中,然后将其渲染到dom上:

    ReactDOM.render(
      <ul>{listItems}</ul>,
      document.getElementById('root')
    );
    

    上面的代码在屏幕上输出了标为1-5的数字列表。

    基本列表组件

    通常情况下,你需要在一个组件中渲染一个列表,我们可以重写上面的例子,让创建的组件接收这个数字数组,然后返回一个无序列表:

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

    当你运行上面的代码时,会报出一串警告:必须为列表的每一个项目提供关键字key。当你创建列表是,必须为每一个项目指定特殊的key属性,我们将在下一章节讨论为什么这一点是非常重要的。
    我们来给每一个列表项目指定关键字以解决上述问题:

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

    关键字

    关键字可以帮助react确定哪些列表项被改变,添加或者移除。关键字应该被指定给列表中的每一项以便它们有一个确定的ID:

    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((number) =>
      <li key={number.toString()}>
        {number}
      </li>
    );
    

    你通常会从你的数据中获取ID来为每一项指定关键字:

    const todoItems = todos.map((todo) =>
      <li key={todo.id}>
        {todo.text}
      </li>
    );
    

    如果你没有一个确定的ID赋给列表项目的话,你可以使用列表的索引值来当作它的关键字:

    const todoItems = todos.map((todo, index) =>
      // Only do this if items have no stable IDs
      <li key={index}>
        {todo.text}
      </li>
    );
    

    如果这些列表项会被重新排序的话,我们并不建议你使用索引值来当作其关键字,因为这样会使得渲染变的缓慢。

    基于关键字抽象组件

    关键字仅仅在在包裹它的数组中起作用。比如,如果你抽象出一个名为ListItem的组件,你应该将关键字添加在ListItem的声明上,而不是在LIstItem组件中绑定关键字:

    • 错误的用例
    function ListItem(props) {
      const value = props.value;
      return (
        // Wrong! There is no need to specify the key here:
        <li key={value.toString()}>
          {value}
        </li>
      );
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // Wrong! The key should have been specified here:
        <ListItem value={number} />
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />,
      document.getElementById('root')
    );
    
    • 正确的用例
    function ListItem(props) {
      // Correct! There is no need to specify the key here:
      return <li>{props.value}</li>;
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // Correct! Key should be specified inside the array.
        <ListItem key={number.toString()}
                  value={number} />
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />,
      document.getElementById('root')
    );
    

    ** 正确的规则是在map函数中绑定关键字 **

    一个列表中的列表项的关键字是唯一的

    在一个列表中,所有列表项的关键字必须是唯一的,当然,这仅仅在这个列表中如此,全局范围内的列表项的关键字不必全都不一样。我们可以将两个相同的关键字用在不同的数组中:

    function Blog(props) {
      const sidebar = (
        <ul>
          {props.posts.map((post) =>
            <li key={post.id}>
              {post.title}
            </li>
          )}
        </ul>
      );
      const content = props.posts.map((post) =>
        <div key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      );
      return (
        <div>
          {sidebar}
          <hr />
          {content}
        </div>
      );
    }
    
    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(
      <Blog posts={posts} />,
      document.getElementById('root')
    );
    

    关键字为React提供了一个追踪的属性,你不需要将它传递到组件内部,如果在你的组件内部需要这个关键字的值,你可以将它赋值给不同的命名变量并通过prop传递到组件内部:

    const content = posts.map((post) =>
      <Post
        key={post.id}
        id={post.id}
        title={post.title} />
    );
    

    在上面的例子中,Post组件可以取得props,id的值,但是取不到props.key的值。

    在JSX中插入map函数

    在上面的例子中我们定义一个ListItems的变量并将其插入到JSX中:

    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    

    JSX允许我们将表达式插入其中,所以我们可以这样写:

    function NumberList(props) {
      const numbers = props.numbers;
      return (
        <ul>
          {numbers.map((number) =>
            <ListItem key={number.toString()}
                      value={number} />
          )}
        </ul>
      );
    }
    

    有时候,上面的表达式是十分简洁的,但是也有些许困惑,就像在javascript里面一样。现在,是使用这种简洁的方式呢,还是像前面的代码一样将其抽象成一个变量呢,完全取决于你。还有,若是map函数中的嵌套的话,将嵌套的东东抽象成一个组件是很棒的实践方式。

    相关文章

      网友评论

        本文标题:列表和关键字

        本文链接:https://www.haomeiwen.com/subject/xijhwttx.html