在新context API出来的时候,就已经有人提出可以用context进行状态管理。react-hooks的更新,使得这一想法的实现更为方便。以一个例子组件进行分析。

前置条件:阅读过react官方文档中,context这一与hooks这一
中文版:context hooks

需求

我们需要实现这样一个组件:

  • 内容可变的,也就是说,具有state
  • 内容的变化是组件自己更新的,譬如:一个按钮与一段文本组成的组件,点击一下按钮,文本内容便多出一段
  • 该组件的可变内容,可以被外部组件(非子组件)获取。第二点的例子里,文本内容可以被其他组件读取到。
  • 该组件暴露内容的方式尽量简单

分析

这是很常见的需求,尤其是在jQuery时期,是一种复用性极高的组件。实现的思路也很简单:

第一种方法,按照纯react目前提供的数据流,父组件(外部组件)将方法作为该组件的props传进来。此处不提。

第二种方法,该组件有一个全局变量,保存了state。当该组件被复用时,将该组件的全局变量merge到整个APP的全局变量上。APP的其他组件通过访问全局变量来访问该组件的state。

第二种方法很容易让人想到redux等状态管理库。但实际上,context + react-hooks已经基本能满足需求。这里分享的是思路,而不是一个新lib的说明书。我也一直以为,可实践的思路远比一个实现好的库有用。

实现

全局变量选定是context。与redux相仿,为了数据流可控,这里也采用reducer接收dispatch(action),从而引起store(这里是context)变化,这样的数据流。

假设我们要实现的组件叫Editor

定义action

Editor/actionTypes.js

export const ADD_PARA = 'ADD_PARA'

Editor/actions.js

import { ADD_PARA } from './actionTypes'export const addPara = para => ({type: ADD_PARA,para,
})

编写reducer

Editor/reducer.js

import { ADD_PARA } from './actionTypes'
import { composeReducer } from '../utils'const reducer1 = (state, action) => {switch (action.type) {case ADD_PARA: {return [action.para, ...state]}default: {return state}}
}const reducer = composeReducer(reducer1)
//自己实现一个工具方法,可以合并reducer,当然这里只有一个reducerexport default reducer

hooks实现context的api

Editor/context.js

这个文件里,我们编写需要暴露给外部的api。因为依赖context,实际上能够暴露出去的只有三个api:ProviderConsumerContext

作为createContext()返回的Context对象,本身具有ProviderConsumer两个属性。Providervalue属性的值应为context的初始值,而且必须在此设值。

这里有一个小小的坑点;createContext()方法的参数,并不是初始值,其参数仅仅是为了在Provider不存在的情况下初始化context,英文文档这里写得比较明确。所以实际意义上的initValue应该在Providervalue属性设值。
The defaultValue argument is only used when a component does not have a matching Provider above it in the tree. This can be helpful for testing components in isolation without wrapping them. Note: passing undefined as a Provider value does not cause consuming components to use defaultValue.

useReducer方法可以基于给定reducer返回dispatch方法

全局变量的值与改变值的方法一并作为context传入。这样使得Editor组件本身可以改变自己的state

基于以上原因与需求第四点,如下实现:

import React, { createContext, useReducer } from 'react'import reducer from './reducer'const EditorContext = createContext()
const initContext = []//封装一下Provider,为其设初始值
const EditorProvider = props => {const [state, dispatch] = useReducer(reducer, initContext)return (<EditorContext.Provider value={{ state, dispatch }}>{props.children}</EditorContext.Provider>)
}const EditorConsumer = EditorContext.Consumerexport { EditorContext, EditorConsumer, EditorProvider }

view

Editor/view.js

实现逻辑非常简单,所以这里暂不区分容器组件与傻瓜组件

useContext方法可以获取context的值,并在context变动时重新渲染

import React, { useContext } from 'react'import { EditorContext } from './context'
import { addPara } from './actions'const Editor = props => {const { state, dispatch } = useContext(EditorContext)return (<>{state.map(content => (<p key={content + Math.random()}>{content}</p>))}<button onClick={() => dispatch(addPara('gggg'))}>add</button></>)
}export { Editor }

导出

Editor/index.js

export { Editor } from './view'
export { EditorContext, EditorProvider, EditorConsumer } from './context'

这样,一个满足要求的Editor组件就实现完成了,该组件由一个文本区域与一个button组成,每次点击button,文本区域会增加一个值为ggggp段落

调用

App.js

调用该组件,实际上是把导出的Provider作为共同父组件即可

import React from 'react'import { Editor, EditorProvider } from './Editor'
import Exp from './Exp'
import './App.css'const App = props => (<EditorProvider className="App"><Editor /><Exp /></EditorProvider>
)export default App

Exp/index.js

import React, { useContext } from 'react'import { EditorContext } from '../Editor'const Exp = () => {const { state } = useContext(EditorContext)return (<>{state.map(content => (<p key={content + Math.random()}>{content}</p>))}</>)
}export default Exp

如上,我们把另一个需要访问该组件值的组件Exp与该组件Editor的共同父组件作为ProviderExp可以很方便的访问Editorstate


以上就使用react-hooks与context完成了一个简单的,易复用的react组件。

实现该组件的目的,不仅仅是满足需求,也是为了看到hooks与context相结合,作状态管理的潜力。

友情提示:
目前(2019.02.03),能够使用react-hooks的react版本 "react": "^16.8.0-alpha.1", "react-dom": "^16.8.0-alpha.1"
更多内容,可以参考Facebook的redux-react-hook:它是另一种思路,保留redux,用context与hooks代替react-redux。

hooks组件封装 react_react-hooks amp; context 编写可复用react组件的一种实践相关推荐

  1. 2.vue3医疗在线问诊项目 - _登录模块 ==> 代码片段、css变量主题定制、cp-nav-bar组件封装、svg打包精灵图插件、cp-icon组件封装、表单校验、密码登录、短信验证码登录及两者

    2.医疗在线问诊项目 - _登录模块 ==> 代码片段.css变量主题定制.cp-nav-bar组件封装.svg打包精灵图插件.cp-icon组件封装.表单校验.密码登录.短信验证码登录及两者的 ...

  2. react学习笔记(二)编写第一个react组件

    继续上一节课的内容,打开App.js:会看到如下代码: import React, { Component } from 'react'; //在此文件中引用React,以及reat的组件类 impo ...

  3. element UI 组件封装--搜索表单(含插槽和内嵌组件)

    组件封装–搜索表单 searchForm.vue 可根据需要,参考姓名和工作自行增加更多常用的默认搜索项 <template><div style="padding: 30 ...

  4. react测试组件_测试驱动的开发,功能和React组件

    react测试组件 This article is part of my studies on how to build sustainable and consistent software. In ...

  5. uniapp 子组件 props拿不到数据_总结下React组件间的通讯

    这是个老话题了. 随着组件化开发成为主流,每个组件都有完善的生命周期,大家可以在生命周期内做一些事情,每个组件有自己的状态管理机制.同时,每个组件都是独立的.这能提高大家的开发效率,规范化开发. 今天 ...

  6. Vue组件封装的过程

    Vue组件封装的过程 vue组件的定义 组件(Component)是Vue.js最强大的功能之一 组件可以扩展HTML元素,封装可重用代码 在较高层面上,组件是自定义元素,Vue.js的编译器为他添加 ...

  7. react组件深度解读

    五.React 核心是组件 在 React 中,我们使用组件(有状态.可组合.可重用)来描述 UI . 在任何编程语言中,你都可以将组件视为简单的函数. React 组件也一样, 它的输入是 prop ...

  8. React 组件设计指南

    前言 在我过往的经历里, 在面试与被面之间通常都会夹杂一些关于组件设计方面的问题, 但通常面试官和候选人都只能通过一些实际的项目经历来就设计进行讨论, 相比服务端面试中可能还涉及一些设计原则和基本思路 ...

  9. 能在任意一种框架中复用的组件,太牛了!

    Web Component 是一种 W3C标准支持的组件化方案,通过它可以编写可复用的组件,同时也可以对自己的组件做更精细化的控制.更牛的是,Web Component 可以在任何一种框架中使用,不用 ...

最新文章

  1. 通过Zookeeper动态感知服务器上下线[案例]
  2. java 浮点数精度_Java中浮点数精度问题
  3. c 文件夹打包解包_linux中文档的压缩与打包
  4. Subsequences (easy version)
  5. 嵌入式C语言基础(三)
  6. JDK源码解析之 java.lang.Integer
  7. 【Marva Collins' Way】第三章
  8. 处理table 超出部分滚动问题
  9. Spark SQL应用解析
  10. 会员分享几个平时看榜单常去的网站
  11. java nfc_如何使用java创建简单的NFC程序?
  12. HTML+CSS简单漫画网页设计成品 蜡笔小新3页 大学生个人HTML网页制作作品
  13. Matlab save colormap
  14. Android10 HAL模块的实现
  15. 微信 - 微信小程序
  16. uva1594 水题
  17. 关于抽象类的实验(java 内部类、多态等练习)
  18. Centos7 安装部署apache。简单易上手
  19. 前端web:响应式Web开发优缺点总结
  20. 大创学习记录(四)之yolov3代码学习

热门文章

  1. 数据为桥迈向智能,渤海财险数据架构智能化演进
  2. Faiss源码剖析:类结构分析
  3. 一文带你搞懂从动态代理实现到Spring AOP
  4. 【华为敏捷/DevOps实践】2. Wiki凭什么持续得到开发人员和团队的喜爱
  5. 随笔--四个月培训小结
  6. 【李宏毅机器学习】Convolutiona Neural Network 卷积神经网络(p17) 学习笔记
  7. numpy.reshape(与ndarray.reshape一样)使用方法
  8. C++中cin的常用用法
  9. WORD如何取消文字下方花花绿绿的波浪线?
  10. django异常日志_django 捕获异常和日志系统过程详解