Hook
是React 16.8
的新特性,它可让在不编写class
类组件的状况下使用state
以及其余的React
特性;而Context
是React16.3
版本里面引入新的Context API
,在以往React
版本中存在一个Context API
,那是一个幕后试验性功能,官方提议避免使用,Redux
的原理就是创建在旧的Context API
。如今新的Context ApI
提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法,为数据通信另辟蹊径。javascript
为解决多层嵌套不一样层级组件之间props
数据传递,这种数据传递及其繁杂,并且后期不易进行维护,为避免driling
式数据通信,能够采用redux
进行数据通信。在新版本React 16.8.6
中Context
为咱们带来新的通信方式。css
Context API
组成部分React.createContext
函数:建立context
上下文,参数是一个默认值(须要传递state
数据),state
能够是Object、Array
或者基本类型数据。html
Provider
:由React.createContext
建立返回对象的属性。在Redux vs. The React Context API中比喻成构建组件树中的电子总线
比较形象。java
Consumer
:由React.createContext
建立返回对象的属性。比喻接入电子总线
获取数据。react
Context
vs redux
Context
的context.Provider/Context.Consumer
和redux
的provider/connect
很是类似。Context
采用的是生产者消费者的模式,咱们能够利用高阶函数(Hoc
)模拟实现一个redux
。git
redux
是经过dispatch
一个action
去修改store
数据;在React 16.8.6
版本的React hooks
提供的useredcuers
和useContext
为咱们更方便经过Context+hooks
的形式去打造一个属于本身redux
github
Context
简单例子
Context
设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。redux
Class.contextType
挂载在class
上的 contextType
属性会被重赋值为一个由 React.createContext()
建立的 Context
对象。这能让你使用 this.context
来消费最近 Context
上的那个值。你能够在任何生命周期中访问到它,包括render
函数中。api
Context.Consumer
让你在函数式组件中完成订阅 context
。这须要函数做为子元素(function as a child)这种作法。这个函数接收当前的 context
值,返回一个 React
节点。传递给函数的value
值等同于往上组件树离这个 context
最近的Provider
提供的 value
值。若是没有对应的 Provider
,value
参数等同于传递给createContext()
的 defaultValue
。数组
// Context 可让咱们无须明确地传遍每个组件,就能将值深刻传递进组件树。
// 为当前的 theme 建立一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给如下的组件树。
// 不管多深,任何组件都能读取这个值。
// 在这个例子中,咱们将 “dark” 做为当前的值传递下去。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// 中间的组件不再必指明往下传递 theme 了。
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,而后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
// 也能够按照这种形式获取
function ThemedButton(){
return (
<ThemeContext.Counsumer>
{theme =>(
<Button theme={theme} />
)
}
</ThemeContext.Counsumer>
);
}
复制代码
context
的详细用法能够参考 Context文档
React Hooks
是React 16.8.6
版本为函数式组件添加了在各生命周期中获取state
和props
的通道。可以让您在不编写类的状况下使用 state(状态) 和其余 React 功能。再也不须要写class
组件,你的全部组件都将是Function
。若是想了解更多关于React hooks
信息能够参考Hooks API 参考。
useState
:获取组件state
状态数据,第一个参数是保存的数据,第二参数是操做数据的方法,相似于setState
。可用ES6
的数组解构赋值来进行获取。useEffect
: 网络请求、订阅某个模块、DOM
操做都是反作用,useEffect
是专门用来处理反作用的。在class
类组件中,componentDidMount
和componentDidUpdate
生命周期函数是用来处理反作用的。useContext
:useContext
能够很方便去订阅context
的改变,并在合适的时候重渲染组件。例如上面的函数式组件中,经过Consumer
的形式获取Context
的数据,有了useContext
能够改写成下面:function ThemedButton(){
const value = useContext(ThemeContxet);
return (
<Button theme={value} /> ); } 复制代码
若是习惯了redux
经过reducer
改变state
或者props
的形式,应该比较很好上手useReducers
,useReducers
和useContext
是这篇文章比较重点的API
。
useReducers
:useReducers
能够传入三个参数,第一个是自定义reducer
,第二参数是初始化默认值,第三个参数是一个函数,接受第二个参数进行计算获取默认值(可选)。const [state,dispatch] = useReducer(reducer,initialValue)
复制代码
下面是useReducers
官方示例:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'reset':
return initialState;
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, {count: initialCount});
return (
<> Count: {state.count} <button onClick={() => dispatch({type: 'reset'})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); } 复制代码
redux
具备Provider
组件,经过store
进行传值。在这里,咱们使用Context
模拟实现Provider
和store
传值,完整代码能够参考 simple-redux。
Provider
组件代码中的storeContext
是React.createContext()
函数建立的Context对象。this.props.store
是模拟经过store
传值操做。
import React,{Component} from 'react';
import {storeContext} from './store';
export default class Provider extends Component{
render(){
return (
<storeContext.Provider value={this.props.store}> {this.props.children} </storeContext.Provider> ) } } 复制代码
store
文件,包括reducer
、Context
的建立,initialState
与reducers
的定义。
import React from 'react';
export const storeContext = React.createContext();
export const initialState = {
user:'kiwis',
age:23
}
export const reducer = (state, action)=>{
switch (action.type) {
case 'CHANGENAME':
return {user:'harhao',age:24}
default:
return initialState;
}
}
复制代码
在根组件App.js
中,使用React hooks
d的useReducer
钩子函数,返回更改state
的dispatch
函数。而后把store
数据和dispatch
传递进封装的Provider
组件中。
import React,{useReducer} from 'react';
import Provider from './views/Provider';
import Child from './views/child';
import {initialState as store,reducer} from './views/store';
import './App.css';
function App() {
const [state,dispatch] = useReducer(reducer,store);
return (
<div className="App"> <Provider store={{state,dispatch}}> <Child/> </Provider> </div>
);
}
export default App;
复制代码
在useConext
外包裹一层函数,更好模拟connect
语法。这里采用自定义React hooks
的方法。定义一个自定hook
函数useConnect
,以下所示:
import {useConext} from 'react';
export default function useConnect(props){
return useContext(props);
}
复制代码
在App.js
的子组件Child
中,在redux
中经过connect
高阶函数来传递数据。这里可使用自定义React hooks
函数useConnect
获取state
和dispatch
。
import React,{useContext} from 'react';
import useConnect from './connect';
import {storeContext} from './store';
import DeepChild from './deepChild';
function Child() {
const {state,dispatch}= useConnect(storeContext);
return (
<div className="child"> <p>姓名:{state.user}</p> <p>年龄:{state.age}</p> <button onClick={()=>dispatch({type:'CHANGENAME'})}>changeName</button> <p>deep child:</p> <DeepChild/> </div>
);
}
export default Child;
复制代码
在Child
子组件中,引入DeepChild
组件。经过useContext
获取顶层最近的state
数据。
import React,{useContext} from 'react';
import {storeContext} from './store';
import useConnect from './connect';
export default function DeepChild(){
const {state} = useConnect(storeContext);
return (
<div> {state.user} </div>
)
}
复制代码
child
子组件和DeepChild
孙组件经过useConnect
获取顶层数据,最终运行效果以下所示:
若是喜欢能够给个赞~或星~哟
git地址:github.com/Harhao/simp…
参考文章
React中文文档
[译]2019 React Redux 彻底指南
[译] Redux vs. React 的 Context API
React Hooks 解析(上):基础
React Hooks 解析(下):进阶