在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖于类组件来获取数据,处理数据,并向下传递参数给 UI 组件进行渲染。使用 React Hooks 相比于从前的类组件有以下几点好处:
Hook 是 React 16.8.0 版本增加的新特性,可以在函数组件中使用 state
以及其他的 React 特性
。
Hooks只能在函数式组件中使用,既无状态组件(所有钩子在用时都要先引入)
Hook 就是JavaScript 函数
,但是使用它们会有两个额外的规则:
1、只能在函数最外层调用 Hook
。不要在循环、条件判断
或者嵌套函数(子函数)
中调用。
2、只能在 React 的函数组件
中调用 Hook
。不要在其他 JavaScript 函数中调用。
3、在多个useState()
调用中,渲染之间的调用顺序
必须相同
。
提供
了一个无需
为每层组件手动添加的 props
,就能在组件树间
进行数据传递
的方法。目的是
为了共享
那些对于一个组件树而言是“全局”的数据
,例如当前认证的用户、主题或首选语言。const value = useContext(MyContext);
createContext 创建一个 Context
对象。useContext来接收
一个 context 对象
(React.createContext 的返回值),并返回该 context 的当前值。当前的 context 值由上层
组件中距离当前组件最近的 的 value prop
决定。当组件上层最近的
时,该 Hook 会触发重渲染
,并使用最新
传递给 MyContext provider 的 context value 值
。
注意:即使祖先使用 React.memo
或shouldComponentUpdate
,也会
在组件本身使用 useContext 时重新渲染
别忘记 useContext 的参数必须是 context 对象本身:
useContext(MyContext)
DemoContext.js组件——创建一个Context对象
import React , {createContext} from 'react'
const DemoContext = createContext()
export default DemoContext
Demo1.js(爷爷组件)——利用Context的Provider注入value属性
import React,{useState} from 'react';
import DemoContext from './DemoContext'
import Demo2 from './Demo2'
const Demo1 = () => {
const [ num , setNum ] = useState(0)
const handleAddClick = () => {
setNum(num=>num+1)
}
const handleSubClick = () => {
setNum(num => num -1)
}
return (
console.log('爷爷组件'),
<div style={{backgroundColor:'yellow'}}>
<h1 >爷爷组件</h1>
<DemoContext.Provider value={{num , handleAddClick , handleSubClick}}>
{num} <br/>
<Demo2></Demo2>
</DemoContext.Provider>
</div>
);
};
export default Demo1;
Demo2.js(爸爸组件)
import React from 'react';
import Demo3 from './Demo3'
const Demo2 = () => {
return (
<div style={{backgroundColor:'yellowGreen'}}>
<h2>爸爸组件</h2>
<div>
<Demo3></Demo3>
</div>
</div>
);
};
export default Demo2;
Demo3.js(儿子组件)——useContext读取Context对象,拿到传递的value
import React ,{useContext}from 'react';
import DemoContext from './DemoContext'
const Demo3 = () => {
const aaa = useContext(DemoContext)
console.log('111',aaa ) // 111 {num: 0, handleAddClick: ƒ, handleSubClick: ƒ}
return (
console.log('儿子组件',aaa ),
<div style={{backgroundColor:'pink'}}>
<h3>儿子组件</h3>
<div>
<button onClick={aaa.handleSubClick}>-</button>
{aaa.num}
<button onClick={aaa.handleAddClick}>+</button>
</div>
</div>
);
};
export default Demo3;
与实例一相似,不过实例二把Context对象
和Provider
单独抽取出来
MyContext.js ——创建Context对象;利用Provider注入value;向外暴露
import React , {createContext, useState} from 'react';
const MyContext = createContext()
const Context = (props) => {
const [ num , setNum ] = useState(0)
const handleAddClick = () => {
setNum(num=>num+1)
}
const handleSubClick = () => {
setNum(num => num -1)
}
return (
<MyContext.Provider
value={{num,handleAddClick,handleSubClick}}
>
{props .children}
</MyContext.Provider>
);
};
export {
Context,
MyContext
} ;
Demo1.js(爷爷组件)——引入的Provider函数,包裹在最外层
import React, { useState } from 'react';
import {Context} from './Context'
import Son from './Son'
const GrandFather = () => {
return (
<Context>
<div>我是爷爷</div>
<Son></Son>
</Context>
);
};
export default GrandFather;
Demo2.js(爸爸组件)
import React from 'react';
import Children from './Children'
const Son = () => {
return (
<div>
我是儿子
<Children></Children>
</div>
);
};
export default Son;
Demo3.js(儿子组件)——useContext读取Context对象,拿到传递的value
import React , {useContext }from 'react';
import {MyContext} from './Context'
const Children = (props) => {
const bbb = useContext(MyContext)
console.log('bbb',bbb)
return (
<div>
<h3>我是孙子</h3>
<div>
<button onClick={bbb.handleAddClick}>+</button>
num:{bbb.num}
<button onClick={bbb.handleSubClick}>-</button>
</div>
</div>
);
};
export default Children;
以实例一为准,多添加一个名字为TemContext的Context对象
DemoContext.js——组件向外暴露两个Context对象(DemoContext和TemContext)
import React , {createContext} from 'react'
const DemoContext = createContext()
const TemContext = createContext()
export {
DemoContext,
TemContext
}
Demo1.js ——两个Context的Provider互相嵌套
import React,{useState} from 'react';
import {DemoContext,TemContext} from './DemoContext'
import Demo2 from './Demo2'
const Demo1 = () => {
const [ num , setNum ] = useState(0)
const [ val , setVal ] = useState({name:'张三'})
const handleAddClick = () => {
setNum(num=>num+1)
}
const handleSubClick = () => {
setNum(num => num -1)
}
return (
console.log('爷爷组件'),
<div style={{backgroundColor:'yellow'}}>
<h1 >爷爷组件</h1>
<DemoContext.Provider value={{num , handleAddClick , handleSubClick}}>
<TemContext.Provider value={val}>
{num} <br/>
<Demo2></Demo2>
</TemContext.Provider>
</DemoContext.Provider>
</div>
);
};
export default Demo1;
Demo2.js —— 没变
import React from 'react';
import Demo3 from './Demo3'
const Demo2 = () => {
return (
<div style={{backgroundColor:'yellowGreen'}}>
<h2>爸爸组件</h2>
<div>
<Demo3></Demo3>
</div>
</div>
);
};
export default Demo2;
Demo3.js —— 利用useContext读取两个Context对象,进行操作
import React ,{useContext}from 'react';
import {DemoContext ,TemContext}from './DemoContext'
const Demo3 = () => {
const aaa = useContext(DemoContext)
const bbb = useContext(TemContext)
return (
console.log('儿子组件',aaa ),
console.log('bbb',bbb),
<div style={{backgroundColor:'pink'}}>
<h3>儿子组件</h3>
<div>
<button onClick={aaa.handleSubClick}>-</button>
<div>DemoContext的:{aaa.num}</div>
<div>TemContext的:{bbb.name}</div>
<button onClick={aaa.handleAddClick}>+</button>
</div>
</div>
);
};
export default Demo3;