文档章节

React学习(3)——列表、键值与表单

随风溜达的向日葵
 随风溜达的向日葵
发布于 2016/11/29 23:08
字数 2205
阅读 156
收藏 4
点赞 0
评论 0

本文记录了在官网学习如何使用JSX+ES6开发React的过程。 。

全文共分为3篇内容:

  1. JSX语法与React组件
  2. 状态、事件与动态渲染
  3. 列表、键值与表单

    扩展:webpack搭建React开发环境

列表与组件的键值

    首先让我们看看在JavaScript中我们是如何处理一个列表的:

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

    例子中使用map方法将每个元素的值*2,最后得到的数组为:[2, 4, 6, 8, 10]。在React中,处理组件数组的方式与之类似。

渲染多个组件

    下面的例子,我们使用map()方法来创建组件中的一系列元素:

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

    listItem就是一个包含多个<li>标签的组件。然后我们将listItem用<ul>标签包裹起来并在浏览器呈现:

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

测试代码

    通过类似的方法,我们可以使用数组来创建一系列元素。

基于列表的组件

    大部分情况,我们希望在一个组件中完成一个列表元素的渲染。将前面的例子稍加修改:

//构建组件
function NumberList(props) {
  const numbers = props.numbers;
  //根据输入的参数获取一个<li>标签的列表
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  //用<ul>包裹<li>并返回
  return (
    <ul>{listItems}</ul>
  );
}
//设置输入参数
const numbers = [1, 2, 3, 4, 5];
//渲染组件
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

   当我们执行这个例子的代码时,会发现在浏览器中输出一个警告:" a key should be provided for list items"。"键值(Key)"在创建列表元素时是一个附加的属性,下一节会详细说明使用它的原因。

    通过number.map()方法向组建中的元素增加键值:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    //根据number输出设置li的key
    <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中,键值(keys)用来标记那些元素被修改了。在使用数组时,应该给数组元素标记键值以便于批量更新的效率:

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

    最好使用一个字符串来表示key值,并且确保兄弟节点之间的唯一性。例如使用业务id作为键值:

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

    在某些情况下无法获取到合理的id值,可以直接使用列表索引:

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

    如果列表中的元素可以重新排序,建议不要使用索引作为键值,这样会导致渲染缓慢。如果你对键值(keys)的使用有浓厚的兴趣,参看:in-depth explanation about why keys are necessary

使用键值扩展组件

    键值仅仅在最外层列表中存在意义。例如,如果想抽取出一个名为ListItem的组件,最好在<ListItem />上标记key值,而不是组件中的<li>元素上。

    下面是一些错误使用键值的例子:

function ListItem(props) {
  const value = props.value;
  //不应该在这里使用键值
  return (
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  /**建议在这里使用并标记键值*/
  const listItems = numbers.map((number) =>
    <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) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <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')
);

键值需要与兄弟节点保证唯一

    在使用的过程中,键值只要保证和兄弟节点的键值没有碰撞即可,并不需要全局唯一。在不同的列表中我们可以使用相同的key:

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')
);

测试代码

    在上面的例子中sidebar、content是两个不同的队列,但是使用了相同的key值。

    键值虽然显示的设置到元素或组件上,但是并不能在组件内部直接获取,如果需要使用键值,我们需要另外设置:

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

    这样,在Post组件中可以通过this.props.id获取到id值,而this.props.key获取不到任何值。

将map()方法嵌入到JSX中

    在下面的例子中,我们直接在map()方法中生成ListItem:

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

    JSX允许在大括号"{}"中嵌入任何表达式,因此我们可以直接嵌入map()方法使用:

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

测试代码

表单

    因为表单元素都保持着一些内部状态,所以HTML的表单与React的表单工作方式有一些区别。例如在标准的HTML表单只接收单个名称:

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

    在用户提交表单时,浏览器默认会跳转到新的页面,当然在默认情况下React中的表单也是这样工作的。但是在大多数情况下,在用户提交数据到后台之前需要使用JavaScript来验证某些数据的合法性。实现这一点的方法我们称之为“controlled components(受控组件)”。

受控组件

    在HTML中,<input><textarea>, and <select> 这些表单元素都包含自己的状态,并在用户输入时发生改变。而在React中,可变的状态通常保存在state属性值中,并且只能通过setState来改变。

    我们使用“受控组件”将2者合并,负责渲染表单的React组件还需要控制用户在渲染完毕后的各种输入操作。看下面这个例子:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

测试代码

    例子中通过在onChange中注册this.handleChange方法来记录值的改变,在改变时会通过setState()设置this.state值,并使用render渲染。此外,组件还用this.handleSubmit来拦截提交事件。这个例子中的组件称之为"受控组件"。

    在受控组件中,每一个状态值的改变都会有一个相关处理函数来处理,这样可以直接修改或验证用户的输入。例如下面这个例子,我们将所有的输入强行变成大写:

handleChange(event) {
  this.setState({value: event.target.value.toUpperCase()});
}

textarea标签

    在HTML中,<textarea>由其子元素来定义文本:

<textarea>
  Hello there, this is some text in a text area
</textarea>

    在React中,<textarea>使用一个value属性来代替子元素。这样使用<textarea>标签与使用单行输入元素(<input type="text">)类似:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'Please write an essay about your favorite DOM element.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

    在这里例子中,在构造函数就初始化了this.state.value。因此<textarea>会显示一个初始值。

select标签

    在HTML中,select会创建一个下拉菜单,例如:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

    由于"cocount"设置了selected属性,所以默认状态下这个<option>是被选中的。在React中,<select>元素使用value元素来设定这个默认值,这在受控组件中使用更方便,因为只需要在一个地方更新它:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite La Croix flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

测试代码

受控组件的替代方案

    在某些情况下使用受控组件会非常的繁琐,因为它针对所有的变更都需要编写一个处理器来管理对应的状态。React官网推荐使用"非受控组件"技术来解决这个问题—— uncontrolled components,它是用于实现输入表单的替代技术。

原文地址:https://www.chkui.com/article/react/react_list_key_and_form

© 著作权归作者所有

共有 人打赏支持
随风溜达的向日葵
粉丝 198
博文 62
码字总数 136492
作品 0
广州
其他
React从零开始(4)——表单和列表

表单是前端开发中必不可少的组件,React作为前端框架,如果不能处理表单,就会被亿万的前端工程师吐槽的。然而React对于表单的处理,还是有一些细节上的东西需要关注,接下来我们详细的描述在...

心扬
2017/12/20
0
0
ReactJS学习笔记——组件复合及表单的处理

ReactJS学习笔记——组件复合及表单的处理 React是一个JavaScript库文件,使用它的目的在于能够解决构建大的应用和数据的实时变更。该设计使用JSX允许你在构建标签结构时充分利用JavaScript的...

小米墨客
2016/03/26
3.5K
3
React Native第3天——常用组件和常见Q&A

我(web+android开发经验)学习React Native过程中接触的知识点和学习的线路图。 React Native第1天——环境配置及知识体系(http://my.oschina.net/addcn/blog/647290) 掌握环境配置及运行h...

addcn
2016/03/30
210
0
[译] 项目什么时候需要 React 框架呢?

原文地址:When Does a Project Need React? 原文作者:CHRIS COYIER 译文出自:掘金翻译计划 译者:龙骑将杨影枫 校对者:Guangyuan (Charlie) Yang、薛定谔的猫 项目什么时候需要 React 框...

龙骑将杨影枫
2017/05/04
0
0
[译]Angular vs React:谁更适合前端开发

原文地址:Angular vs. React: Which Is Better for Web Development? 原文作者:Brandon Morelli 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:龙骑将杨影枫 校对...

龙骑将杨影枫
2017/09/03
0
0
深入理解React(二) —— 数据流和事件原理

版权声明:本文由左明原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/158 来源:腾云阁 https://www.qcloud.com/community 这个,叫做竹笕,是中日传统...

偶素浅小浅
2016/11/08
11
0
别责怪框架:我使用 AngularJS 和 ReactJS 的经验

  在过去的几年里,网站进化成了复杂的网页应用。曾经的互联网只涉及到简单的商业信息展现,而如今,看看 Facebook、Slack、Spotify 以及 Netflix,互联网正在改变你的社交和生活方式。随着...

前端技术栈
2017/01/03
0
0
[译] 使用 Puppeteer 和 Jest 测试你的 React 应用

原文地址:Testing your React App with Puppeteer and Jest 原文作者:Rajat S 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:jonjia 校对者:sunhaokk 老教授 如何...

jonjia
05/14
0
0
你的第一杯Web 2.0 —— 快速浏览jQuery、Spring MVC和XStream/Jettison

作者 Joel Confino译者 张凯峰 发布于 2008年12月12日 上午12时1分 社区 Java 主题 Web 2.0, JavaScript 标签 jQuery, XStream 不再有页面刷新:使用jQuery 在我参与创建的一些Web网站应用中...

晨曦之光
2012/03/09
0
0
通往全栈工程师的捷径 —— React

首先,我们来看看 React 在世界范围的热度趋势,下图是关键词“房价”和 “React” 在 Google Trends 上的搜索量对比,蓝色的是 React,红色的是房价,很明显,人类对 React 的关注程度已经远...

我家有宝
2016/01/14
37
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

实现异步有哪些方法

有哪些方法可以实现异步呢? 方式一:java 线程池 示例: @Test public final void test_ThreadPool() throws InterruptedException { ScheduledThreadPoolExecutor scheduledThre......

黄威
今天
0
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

六库科技
今天
0
0
牛客网刷题

1. 二维数组中的查找(难度:易) 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入...

大不了敲一辈子代码
今天
0
0
linux系统的任务计划、服务管理

linux任务计划cron 在linux下,有时候要在我们不在的时候执行一项命令,或启动一个脚本,可以使用任务计划cron功能。 任务计划要用crontab命令完成 选项: -u 指定某个用户,不加-u表示当前用...

黄昏残影
昨天
0
0
设计模式:单例模式

单例模式的定义是确保某个类在任何情况下都只有一个实例,并且需要提供一个全局的访问点供调用者访问该实例的一种模式。 实现以上模式基于以下必须遵守的两点: 1.构造方法私有化 2.提供一个...

人觉非常君
昨天
0
0
《Linux Perf Master》Edition 0.4 发布

在线阅读:https://riboseyim.gitbook.io/perf 在线阅读:https://www.gitbook.com/book/riboseyim/linux-perf-master/details 百度网盘【pdf、mobi、ePub】:https://pan.baidu.com/s/1C20T......

RiboseYim
昨天
1
0
conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
昨天
1
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
昨天
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
昨天
1
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部