抛开 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

相关文章

SpringBoot返回文件让前端下载的几种方式

《SpringBoot返回文件让前端下载的几种方式》文章介绍了开发中文件下载的两种常见解决方案,并详细描述了通过后端进行下载的原理和步骤,包括一次性读取到内存和分块写入响应输出流两种方法,此外,还提供... 目录01 背景02 一次性读取到内存,通过响应输出流输出到前端02 将文件流通过循环写入到响应输出流

SpringBoot+Vue3整合SSE实现实时消息推送功能

《SpringBoot+Vue3整合SSE实现实时消息推送功能》在日常开发中,我们经常需要实现实时消息推送的功能,这篇文章将基于SpringBoot和Vue3来简单实现一个入门级的例子,下面小编就和大... 目录前言先大概介绍下SSE后端实现(SpringBoot)前端实现(vue3)1. 数据类型定义2.

前端Visual Studio Code安装配置教程之下载、汉化、常用组件及基本操作

《前端VisualStudioCode安装配置教程之下载、汉化、常用组件及基本操作》VisualStudioCode是微软推出的一个强大的代码编辑器,功能强大,操作简单便捷,还有着良好的用户界面,... 目录一、Visual Studio Code下载二、汉化三、常用组件1、Auto Rename Tag2

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

vue监听属性watch的用法及使用场景详解

《vue监听属性watch的用法及使用场景详解》watch是vue中常用的监听器,它主要用于侦听数据的变化,在数据发生变化的时候执行一些操作,:本文主要介绍vue监听属性watch的用法及使用场景... 目录1. 监听属性 watch2. 常规用法3. 监听对象和route变化4. 使用场景附Watch 的