首页 > 其他分享 >react的思想和数据流

react的思想和数据流

时间:2023-04-17 19:33:40浏览次数:40  
标签:content const 思想 react 副作用 state UI 数据流 page

最近忙着写前端界面,粗略讨论以下 react 的函数式编程思想和组件通信的应对思路。

纯函数和副作用

函数式编程中函数是一等公民。一个函数的返回值只取决于输入参数时,那么这个函数的行为是确定的,我们称之为纯函数。那么反过来,如果函数的输入参数相同,而返回值不确定,那么该函数就是有副作用的,是不纯的。举几个例子

// 纯函数
const add = (a) => a + 1;

// 有副作用,修改了全局变量,且返回值依赖全局变量。
let a = 0;
const add = (b) => b + a++;

// `read`有副作用,文件就相当于`全局变量`,而write可以随时修改这个`全局变量`
const write = (path) => sync(path);
const read = (path) => fileOf(path);

// `fetchUser`有副作用,因为`putUser`可以修改服务端的用户数据,
// 每次调用`fetUser`的结果一定是不一致的
const putUser(userForm) => fetch("put:/some/uri", userForm);
const fetchUser(userForm) => fetch("/some/uri", userForm);

// 有副作用
// 当用户操作了input,那么函数输出的UI和之前的UI就是不一样的。
function Component() {
    const [state, setState] = useState(init);


    return (
        <input
            value={state}
            onCange={(e.target) => setState(e.target.value)}
        />
    )
}

// useState实际上是设置了一个全局变量
let _state;
function useState(init) {
    if(!_state) = _state = init;
    return [_state, setState];
}
function setState(val) {
    if(_state !== val) _state = val;
    render(Component);
}
function Component() {
    return (
        <input
            value={getter}
            onCange={(e.target) => setter(e.target.value)}
        />
    )
}

总结几个副作用:

IO

磁盘和内存就相当于代码上下文的全局变量,当涉及到同一块内存的读和写,必定会有副作用

网络

服务器的数据库就像于代码上下文的全局变量,当涉及到同一个表项的读和写,必定会有副作用

UI

用户操作的 UI 组件需要一个全局状态模型来记录 UI 中显示的状态,当涉及到同一个状态的读和写,必定会有副作用。

因此我们可以轻易总结出来,当函数内修改的变量超过了函数的生命周期,那么该函数一定是有副作用的。

读副作用

react中的每一个state都是全局生命周期变量,对每次产生的UI都有副作用。但是在函数组件内部执行的过程中,需要和外部的全局变量同步,那么就需要 useEffect(),下面是例子

function Pagination() {
    const [page, setPage] = useState(1);
    const [content, setContent] = useState<string>(init);

    useEffect(() => {
        const body = fetch(`/fetch/content?offset=${page}`);
        setContent(body.content);
    }, [page])
    return (
        <p>{content}</p> 
        {pageIndex.map((index) => (
        <div onClick={() => setPage(index)}>
            {index}
        </div>
        ))}
    )
}

理论上如果一开始就获取所有的内容,那么副作用就从服务器转移到了react的状态模型,就没有这种写法。但是单页应用为了兼顾开销和延迟不得不在后期方位这些副作用。

pageUI双向绑定,是UI副作用变量。我们需要通过page来和服务器同步content,那么这里的content则是一个缓冲区,一个临时变量,即读副作用。上边的写法经过编译将产生如下代码:

let _page;
function usePage(init)...
function setPage(val)...

let _content; // 应该是局部缓冲区,但是被用作全局。
...
function Pacination() {
    ...
}

理性的写法应当如下:

function Pagination() {
    const [page, setPage] = useState(1);
    let content = "";  // 缓冲区内置。

    useEffect(async () => {
        const body = await fetch(`/fetch/content?offset=${page}`);
        content = body.content;
        render(Pagination) // 由于useEffect 在render函数之后执行,
                           // 我们需要自己render

    }, [page])
    ...
}

开销

这时候肯定有人会问:setContent 修改和 setPage 为何不能合并呢?答案:得益于react的虚拟dom,每次render是差值更新而非全量更新。因此多次渲染的开销理论上很少。

全局统一状态

这时候就有人想到了,如果我将 page 和 content 合体,放在一个大 state 里,那么每次不就能只setState一次了吗?这就是 redux 等状态管理库的由来。通过将UI不可更改的state(或者依赖的state,通常为局部缓冲区)包装起来。

读写副作用

即读和写的变量都在react外部,考虑到一个读写副作用的例子:

function UserSettings() {
    const [username, setUsername] = useState("");

    useEffect(() => {
        const body = fetch("some/uri");
        setUsername(body.username);
    }, []);

    return (
        <>
        <input
            value={username}
            onChange={(e) => setUsername(e.currentTarget.value)}
        />

        <button onClick={() => {
            fetch(`put:some/uri?username=${username}`);
        }} />
        </>
    )
}

显然这里的username不仅和UI双向绑定,还和服务器双向绑定。但是显然UI和服务器是不同步的,因为即使我们本地修改了username并点击了按钮,如果服务器没有更新的的话,那么刷新之后username又变了回去。我的看法是UI端无需对后端的一致性负责,username只能负责读缓冲区,而不能负责同步。因此大可不必纠结单页应用的一致性比多页应用负担大。

单向数据流

react通过组件化来分解大量缓冲区state的耦合。

读副作用

拿上边的pagination举例

function Pagination() {
    const [page, setPage] = useState(1);
    const [content, setContent] = useState<string>(init);

    useEffect(() => {
        const body = fetch(`/fetch/content?offset=${page}`);
        setContent(body.content);
    }, [page])
    return (
        <PageContent page={page} />
        {pageIndex.map((index) => (
        <div onClick={() => setPage(index)}>
            {index}
        </div>
        ))}
    )
}

function PageContent({ page }) {
    const [content, setContent];
    useEffect(() => {
        const body = fetch(`/fetch/content?offset=${page}`);
        setContent(body.content);
    }, [page]);

    return <p>{content}</p> 
}

这样page就成了函数参数,我们将PageContent改造成了一个纯函数,缓冲区就被下方到这个组件中。page更新

标签:content,const,思想,react,副作用,state,UI,数据流,page
From: https://www.cnblogs.com/www159/p/17323988.html

相关文章

  • React onBlur回调中使用document.activeElement返回body解决方案
    最开始想实现一个功能,点击img图标后给出购物下拉框CartDropdown,当img及CartDropdown失去焦点时隐藏CartDropdown。最开始的核心代码如下:exportdefaultfunctionCart(){ const[isCartOpen,setIsCartOpen]=useState(false) functionclickHandler(){ setIsCartOpen(......
  • 10分钟理解React生命周期
    前言学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助.一、简介React /riˈækt/ 组件的生命周期指的是组件从创建到销毁过程中所经历的一系列方法调用。这些方法可以让我们在不同的时刻执行特定的代码,以满足组件的需求。React的生命周期......
  • Nginx之数据流代理stream模块简介和使用
    转自 http://t.csdn.cn/RV4Hi一、stream模块简介  stream模块一般用于TCP/UDP数据流的代理和负载均衡,通过stream模块我们可以代理转发tcp报文。ngx_stream_core_module模块从1.9.0版开始提供。默认情况下,此模块不是构建的,应该使用–withstream配置参数启用它,即我们需要使用.......
  • Stream流的思想和获取stream流
       stream流打印单列集合://单列集合获取ArrayList<String>list=newArrayList<>();Collections.addAll(list,"a","a","a");//stream流Stream<String>stream=list.stream();//用终结方法打印所有数据stream.forEach(newConsumer<St......
  • react+ts+hook封装一个table分页组件(建议收藏,直接使用)
    前言大家好我是歌谣我是一名坚持写博客四年的博主最好的种树是十年前其次是现在,今天继续对antdesigntable的分页封装进行讲解封装准备(多看官网)jsx风格的api<><Table<User>columns={columns}dataSource={data}/>/*使用JSX风格的API*/<Table<User>data......
  • 基于 RocketMQ Connect 构建数据流转处理平台
    作者:周波,阿里云智能高级开发工程师,ApacheRocketMQCommitter01从问题中来的RocketMQ Connect在电商系统、金融系统及物流系统,我们经常可以看到RocketMQ的身影。原因不难理解,随着数字化转型范围的扩大及进程的加快,业务系统的数据也在每日暴增,此时为了保证系统的稳定运行,就需......
  • 基于 RocketMQ Connect 构建数据流转处理平台
    作者:周波,阿里云智能高级开发工程师,ApacheRocketMQCommitter01从问题中来的RocketMQ Connect在电商系统、金融系统及物流系统,我们经常可以看到RocketMQ的身影。原因不难理解,随着数字化转型范围的扩大及进程的加快,业务系统的数据也在每日暴增,此时为了保证系统的稳定运行,就......
  • day09 react完整手写
     实现Hooks的数据结构fiberNode中可用的字段:memoizedStateupdateQueue  实现useState包括2方面工作:实现mount时useState的实现实现dispatch方法,并接入现有更新流程内 ......
  • 论Vue和React的不同之处
    论Vue和React的不同之处Vue和React都是用于构建UI界面的流行框架。它们的哲学也有很多相似的地方,我们可以认为这些特性是流行前端框架的一个趋势。它们是:组件化。将结构、样式、脚本进行耦合,让界面一部分区域能够独立出来,并可以提供复用;声明式。摒弃了JQuery那种手动......
  • 构建React-app应用时create-react-app卡住超慢的解决办法
    解决方案是换源,这个解决方法是从网上找到的,特此整理过来收藏一下。虽然平常使用cnpm来代替npm,但也只是使用新的指令而已。而在寻求create-react-app的相关配置希望修改registry时失败了,最后发现create-react-app指令默认调用npm,于是直接把npm的register给永久设置过来就好了,这样使......