抛开 React 学习 React(1)

2024-03-06 09:58

本文主要是介绍抛开 React 学习 React(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先阅读下 jQuery 实现的 TodoMVC 源码。
也许你会注意到有一个叫 render 的方法,他会在某个事件触发或者数据更新的时候被调用。现在,我们从头来实现一个例子:当 input 的值改变时,调用 render 函数,并且更新 DOM 元素。

    var state = {value: null}$('#input').on('keyup', function () {state.value = $(this).val().trim();render();})function render(){$('#output').html(state.value)}render();

我们使用一个全局变量 state 来同步所有的东西。也就是说,当 input 的值改变时会更新两样东西:1. 更新整个应用的 state 2. 更新 DOM(根据应用当前的 state 来调用 render 函数)
现在,我们有了一个新想法:

    function output(text){return '<div>' + text + '</div>'}

那么接下来:

   function h2(text){return '<h2>' + text + '</h2>';}function div(text){return '<div>' + text + '</div>';}function header(text){return div(h2(text));}console.log(header('foo') === '<div><h2>foo</h2></div>');   // true

上面的函数都是基于一个 text(input) 然后返回一个 string(text) 。调用 header 的时候传入相同的参数( input ),都会得到相同的字符串( output )。如果你在想思考 React 中的 stateless functions 的话,那么这个其实就是一个简化版。只是 Stateless functions 会返回一个 React Element 而不是一个简单的 string,但是思路是一样的。
既然这样,我们就把这个想法应用到我们之前的例子中。我们添加了一个 button ,用来添加 todo item 。

    var state = {items: [], id: 0};//click回调事件操作了数据,并没有直接操作DOM$('#add').on('click', function (e) {var value = $('#input').val().trim()$('#input').val('')state.items.push({id: state.id++,text: value,completed: false})render();})//click回调事件操作了数据,并没有直接操作DOM$('#list').on('click', function () {var toggleId = parseInt($(this).attr('id'));state.items.forEach(function (el) {el.id === toggleId && (el.completed = !el.completed)})render();})function render () {var items = state.items.map(function (item) {var completed = item.completed ? 'completed' : '';return '<li class="item + ' + completed + '" id="' + item.id + '">(' +item.id + ') ' + item.text + '</li>'}).join('');var html = '<ul>' + items = '</ul>';$('#list').html(html);}render();

在上面,我们定义了两个 click 事件,当他们触发时就会更新我们的 state 以及调用 render 函数。而 render 函数会创建一个 todo list 。 state 作为中间媒介,简化了事件和 DOM 元素之间的交互,而不是通过事件来直接操作 DOM (不需要定义每个 DOM 元素和每个事件以及他们之间的关系)。当某个 action (如 click 事件) 触发之后, state 就会更新,接着调用 render 函数,最后我们的应用就会更新。这样一来,就简化了好多复杂的交互。
可以看到, render 函数有一点乱。我们不妨创建一个函数,他接收一个参数(input),然后基于这个参数返回一个字符串(output)。

    function ItemRow (props) {var className = props.completed ? ' item completed' : 'item'return '<li className="' + className +' ">' + props.text + '</li>'}function ItemsList (props) {return '<ul>' + props.items.map(ItemRow).join('') + '</ul>'}function render (props) {$('#list').html(ItemsList({items: props.items}))}

render 函数并不依赖外部的状态(state),这使得我们在调用 render 时可以随便传入一个 input ,也就意味着我们的应用重新渲染时,相同的 input 会有相同的 output 。需要注意的是,DOM 操作其实是一个 side effect,但是现在我们暂时忽略他。
把 state 从 render 函数中分离出来,可以使得我们很容易实现 Undo/Redo 。
另外一个优化就是传一个 root node 作为参数,而不是写死在 render 函数里面:

   function render (props, node) {node.html(ItemsList({items: props.items}))}

因此,我们可以这样调用 render 函数:

   render(state, $('#list'))

我们会很容易想到:当 state 改变的时候,能不能自动地更新应用?也就是,不用手动地调用 render 函数。

现在,我们来创建一个 store ,他的作用是当 state 改变之后,就立马调用 render 函数。下面的实现虽然简单,但也是一个 advanced state container 的雏形。

   function createStore (initialState) {var _state = initialState || {},_listeners = []function updateListeners (state) {_listeners.forEach(function (listener) {listener.cb(state)})}return {setState: function (state) {_state = stateupdateListeners(state)},getState: function () {return _state},onUpdate: function (name, cb) {_listeners.push({name: name, cb: cb})}}}

现在,我们更新 state 只需要简单地调用 setState 方法。只要 state 一改变,我们的 render 函数就会被调用:

    var store = createStore(store)store.onUpdate('rootRender', function (state) {render(state, $('#list'))})

现在我们学会了什么?我们知道了简单的单向数据流(one-way data flow)的原则。我们给 render 函数传了一个 state 参数,然后 state 就会像流水一样,流到 render 函数的每个层次中。比如, ItemRow 函数需要 ItemsList 给他传进正确的参数。

我们已经创建了多个组件(component),并且我们把这些组件组合(compose)在一起。回想一下前面的 header 例子,我们把 div 和 h2 函数组合成了一个 header 函数。并且,这些函数都是 pure function ,这使得所有更新都是可预测的。

并且,我们使用了 store 来管理我们的 state 。

而,React 会用更好更优美的方法来实现上面这些东西。组件(组合),使用 Virtual DOM 优化渲染,单向数据流等等。

这篇关于抛开 React 学习 React(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/779668

相关文章

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)

HTML中meta标签的常见使用案例(示例详解)

《HTML中meta标签的常见使用案例(示例详解)》HTMLmeta标签用于提供文档元数据,涵盖字符编码、SEO优化、社交媒体集成、移动设备适配、浏览器控制及安全隐私设置,优化页面显示与搜索引擎索引... 目录html中meta标签的常见使用案例一、基础功能二、搜索引擎优化(seo)三、社交媒体集成四、移动

HTML input 标签示例详解

《HTMLinput标签示例详解》input标签主要用于接收用户的输入,随type属性值的不同,变换其具体功能,本文通过实例图文并茂的形式给大家介绍HTMLinput标签,感兴趣的朋友一... 目录通用属性输入框单行文本输入框 text密码输入框 password数字输入框 number电子邮件输入编程框

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.

HTML5 中的<button>标签用法和特征

《HTML5中的<button>标签用法和特征》在HTML5中,button标签用于定义一个可点击的按钮,它是创建交互式网页的重要元素之一,本文将深入解析HTML5中的button标签,详细介绍其属... 目录引言<button> 标签的基本用法<button> 标签的属性typevaluedisabled

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求