原文链接

如果还没有阅读 翻译 | Learning React Without Using React Part 1,请先阅读。

第2部分将接着我们上次讲到的内容。这篇文章将着重于改进我们简单的待办事项列表。当前的实现由一组函数组成,它们呈现完整的应用,并包含一个管理我们状态的简单store。但是,我们需要做一些事情来改进我们的应用。 这里是一个与当前示例和代码的链接。

首先,我们没有妥善处理我们的事件。我们的组件不处理任何事件。在React中,事件触发数据流。 这意味着我们的组件应该触发事件。举个例子我们的ItemRow方法应该调用一个通过props传递过来的方法来执行click事件。我们如何做到这一点?

这是一个初步尝试。

function ItemRow(props) {var className = props.completed ? 'item completed' : 'item';return $('<li>').on('click', props.onUpdate.bind(null, props.id)).addClass(className).attr('id', props.id).html(props.text);
}
复制代码

我们在列表元素中添加了一个事件监听器,当单击该项目时,它将触发一个点击事件。onUpdate函数通过props传递过来。

现在我们需要一个为我们创建元素的函数。

function createElement(tag, attrs, children) {var elem = $('<' + tag + '>');for (var key in attrs) {var val = attrs[key];if (key.indexOf('on') === 0) {var event = key.substr(2).toLowerCase();elem.on(event, val)} else {elem.attr(key, val);}}return elem.html(children);
}
复制代码

通过实现createElement函数,我们可以将ItemRow函数重构为如下所示:

function ItemRow(props) {var className = props.completed ? 'item completed' : 'item';return createElement('li', { id: props.id, class: className, onClick: props.onUpdate.bind(null, props.id) }, props.text);
}
复制代码

需要注意的是,在React的 createElement中创建的是javaScript对象,是用来表示Dom元素,而不是Dom元素本身。另一方面,让我们来看看当您编写JSX时实际发生了什么。

以下JSX示例:

return ( <div id='el' className:'entry'>Hello</div>)
复制代码

被转换为

var SomeElement = React.createElement('div', {id: 'el', className: 'entry'}, 'Hello');
复制代码

调用SomeElement()将返回这样的对象:

{// ..type: 'div', key: null, ref: null, props: {children: 'Hello', className: 'entry', id: 'el' },
}
复制代码

对于更详细的认识,可以读React Components, Elements, and Instances.

回到我们的例子。onUpdate从哪里来?

我们在render中定义了一个updateState函数,并通过props将它传递到ItemList组件。

function render(props, node) {function updateState(toggleId) {state.items.forEach(function(el) {if (el.id === toggleId) {el.completed = !el.completed;}});store.setState(state);}node.empty().append([ItemsList({items: props.items,onUpdate: updateState})]);
}
复制代码

ItemsList方法本身传递onUpdate给每一个ItemRow

function extending(base, item) {return $.extend({}, item, base);
}
function ItemsList(props) {return createElement(‘ul’, {}, props.items.map(extending.bind(null, {onUpdate: props.onUpdate})).map(ItemRow));
}
复制代码

通过采用这种方法,我们实现了以下步骤: 数据流从组件层次结构向下流而响应事件则向上流。 这也意味着我们可以删除先前定义的全局监听器移动到render中,这就是前面提到的updateState。

更多的改进。

让我们用一个方法生成input和button元素。所以最终我们的标记只包含一个div。

<div id="app"></app>
复制代码

例如,可以很容易地创建这样的input元素。

var input = createElement(‘input’, { id: ‘input’ });
复制代码

我们还可以移动一个全局的监听button点击的方法到SearchBar方法中。SearchBar返回一个input和button元素,通过一个来自props中的回调方法来处理点击事件。

function SearchBar(props) {function onButtonClick(e) {var val = $('#input').val();$('#input').val('');props.update(val);e.preventDefault();}var input = createElement('input', { id: 'input' });var button = createElement('button', { id: 'add', onClick: onButtonClick.bind(null)}, 'Add');return createElement(‘div’, {}, [input, button]);
}
复制代码

现在我们的render方法需要调用SearchBar并且传递一个适当的props。在更新render方法之前,让我们花一点时间来思考下如何重构。让我们暂时忽略我们的store处理高级别组件中的状态。直到现在,所有的方法都是无状态的,我们将创建一个方法来处理状态并且在合适的时候更新子组件。

容器组件 让我们创建高级别容器。也可以阅读 Presentational and Container Components 帮助理解。下面应该给你一个更好的建议。

所以我们实现容器组件App。它所做的就是调用SearchBar和ItemList方法,并返回一个元素数组。我们要重新考虑Render方法。大部分代码会简单地进入App组件。

在看App组件之前,让我们快速浏览一下我们的render:

function render(component, node) {node.empty().append(component);
}
render(App(state), $(‘#app’));
复制代码

render现在仅仅负责将应用呈现在给定的节点中。React比这个简单的实现要复杂的多。我们只是将一个元素树附加到一个已定义的根元素中,但它应该足以表达一个高层次的概念。

我们的App组件现在变成了真正的容器组件。

function App(props) {function updateSearchState(value) {state.items.push({id:state.id++, text:value, completed:false});store.setState(state);}function updateState(toggleId) {state.items.forEach(function(el) {if (el.id === toggleId) {el.completed = !el.completed;}});store.setState(state);}return [SearchBar({update: updateSearchState}), ItemsList({items: props.items, onUpdate: updateState})];
}
复制代码

我们还需要再做一件事。我们正在访问一个全局store,并调用setState来重新render。

让我们重构App组件,使其重新绘制他的子组件而无需调用store。我们如何做到这一点?

首先,让我们忽略store并找出如何调用setState方法来重新绘制组件和它的子元素。

我们需要在这个高级组件中跟踪当前状态,并且在setState发生变化时也要注意重新绘制DOM。这里有一个非常原始的方法:

function App(props) {function getInitialState(props) {return { items: [], id: 0 };}var _state = getInitialState(), _node = null;function setState(state) {_state = state;render();}// ...
}
复制代码

我们通过调用getInitialState来初始化我们的状态,当我们通过setState更新状态时,我们调用在App组件中调用它自己的render方法。

创建属于App组件自己的render方法。在render方法中要么创建一个根节点,要么在状态更改时简单地更新节点。

// naive implementation of render…
function render() {var children = [SearchBar({ update: updateSearchState}),ItemsList({ items: _state.items,onUpdate: updateState})];if (!_node) {return _node = createElement(‘div’, { class: ‘top’ }, children);} else {return _node.html(children);}
}
复制代码

这为了表达一个事实,在React组件内调用setState,不绘制完整的应用,只绘制组件和它的子元素,即不调用全局render方法只调用App组件的render方法。

这是更新后的全局render方法的调用。我们创建App组件时没有任何参数,只是依赖于getInitialState返回初始状态。

function render(component, node) {node.empty().append(component);
}
render(App(), $(‘#app’));
复制代码

Check the functioning example including the complete code.

细化

如果我们有一个泛型函数,它会返回一个带有setState函数的对象,并且能够辨别传入的props和组件状态。这便是一个简单的创建组件的方法。

这样的初版:

var App = createClass({updateSearchState: function(string) { //... },updateState: function(obj) { //... },render: function() {var children = [SearchBar({ update: this.updateSearchState}),ItemsList({ items: this.state.items,onUpdate: this.updateState})];return createElement(‘div’, { class: ‘top’ }, children);}
})
复制代码

好消息是,React提供了多个选项来创建组件,包括使用React.createClass。其他选项包括ES6中的class和无状态的函数 for more information consult the docs 。

我们的示例应用程序介绍了组件层次结构中的数据流和事件流。我们已经了解了如何在组件内部处理状态。要了解和学习更多关于React的知识。下面的链接应该有帮助。

进一步的学习

Thinking in React

Getting Started

JSX

React-howto

Removing User Interface Complexity, or Why React is Awesome

Presentational and Container Components

React Components, Elements, and Instances

翻译 | Learning React Without Using React Part 2相关推荐

  1. react jquery_2019年React简介(面向仅了解jQuery的人们)

    react jquery by Julien Benchetrit 通过朱利安·贝肯特里特 2019年React简介(面向仅了解jQuery的人们) (An Introduction to React ...

  2. react hooks_为什么选择React Hooks,我们如何到达这里?

    react hooks by Ryan Yurkanin 瑞安·尤卡宁(Ryan Yurkanin) 为什么选择React Hooks,我们如何到达这里? (Why React Hooks, and ...

  3. react cookie_安全React快速应用程序jsonwebtoken cookie会话auth0和通行证教程

    react cookie I've been a long-time learner of express, node, and react projects. I'm always hopping ...

  4. [译] React 路由和 React 组件的爱恨情仇

    原文地址:The Love-Hate Relationship between React Router and React Components 原文作者:Kasra 译文出自:掘金翻译计划 本文永 ...

  5. React Component vs React Element

    React Component vs React Element 有这样的一个问题: // 方法定义 function add(x, y) {return x + y }// 方法调用 add(1, ...

  6. 如何将React App转换为React Native

    I have been working on a lot of mobile projects lately - including Cordova, PhoneGap, React Native, ...

  7. react hooks使用_何时使用React Suspense和React Hooks

    react hooks使用 React Suspense对Monad就像钩子对应用符号一样 (React Suspense is to a Monad as Hooks are to Applicat ...

  8. 16、React系列之 React 路由

    版权声明:本文为博主原创文章,未经博主允许不得转载. PS:转载请注明出处 作者:TigerChain 地址:http://www.jianshu.com/p/b55cf53e633a 本文出自 Ti ...

  9. 什么是React为什么使用React什么时候使用React

    什么是React? (What is React?) React.js often referred to as React or ReactJS is a JavaScript library re ...

  10. 从零开始React:一档 React环境搭建,语法规则,基础使用

    手挽手带你学React入门第一期,带你熟悉React的语法规则,消除对JSX的恐惧感,由于现在开发中都是使用ES6语法开发React,所以这次也使用ES6的模式进行教学,如果大家对ES6不熟悉的话,先 ...

最新文章

  1. 怎么选择数据服务器?请记住这五条
  2. Linux按照CPU、内存、磁盘IO、网络性能监测
  3. JAVA虚拟机运行数据区
  4. 葡萄城报表V11 SP2新版本震撼发布!
  5. 联想台式机网卡驱动_【装机帮扶站】第339期:联想刃7000:是否还有选购价值?4000价位装机推荐...
  6. java中Object和Objects类、toString方法和equals方法介绍
  7. unknow ’query_cache_size’报错的解决方法吗
  8. Linux本地无法登录,远程却可以登录
  9. Java运行时内存工作过程
  10. 连续与离散变量的函数分布计算
  11. 如何在 NVIDIA GPU、CUDA 和 cuDNN 中使用 OpenCV 的“dnn”模块
  12. 【例】系统顺序图、操作契约、领域模型图
  13. SurfaceView 之满屏的代码雨效果
  14. 【平面设计基础】03:绘制—图标到底有多重要
  15. Python 数据分析 —— Matplotlib ②
  16. Cannot find module ‘node-sass‘问题解决
  17. Frontiers in Neuroscience:弥散张量成像(DTI)研究指南
  18. Oracle数据库的数据备份
  19. 无痕模式运行html,各个浏览器开启无痕模式的方法教程
  20. PHP面向对象基础七

热门文章

  1. 梯度下降法中的参数学习速率如何选择
  2. matlab仿真之大尺度衰落因子2--小区间
  3. itext生成pdf间距_java将html转为pdf
  4. MATLAB模式识别基本操作函数解析
  5. Logistic Regression分类器与softmax分类器
  6. cookielib和urllib2模块相结合模拟网站登录
  7. linux不解压情况下查看压缩包内文件的总行数、文件列表的数目
  8. POJ - 1458(最长公共子序列,动态规划)
  9. vmware ubuntu 16.04 guest 修复不能桌面大小自动调整和从宿主机复制粘贴的问题
  10. 能力提升综合题单 Part 8.7 图的连通性相关