首先创建4个函数,f1(),f2(),f3(),f4()
function f1() {
console.log('f1')
}
function f2() {
console.log('f2')
}
function f3() {
console.log('f3')
}
function f4() {
console.log('f4')
}
f1()
console.log('have done')
然后我们在f1中调用f2, f2中调用f3,f3中调用f4
function f1() {
console.log('f1')
f2()
}
function f2() {
console.log('f2')
f3()
}
function f3() {
console.log('f3')
f4()
}
此时我们可以看到f1,f2,f3,f4逐层调用了。<br />
此时我们有一个场景,需要在这个调用顺序下,让f1传值给f4<br />先给f1调用的地方创建作用域
{
let num = 1000;
f1(num);
console.log("have done");
}
之后我们将值进行逐层传递
function f1(n1) {
console.log("f1", n1);
f2(n1);
}
function f2(n2) {
console.log("f2", n2);
f3(n2);
}
function f3(n3) {
console.log("f3", n3);
f4(n3);
}
function f4(n4) {
console.log("f4", n4);
}
之后我们就把num=1000,传递给了f4函数<br />
接下来我们把这个思路,应用到react组件中。首先创建F1,F2,F3,F4四个组件
function F1() {
return (
<div>
1 <F2 />
</div>
);
}
function F2() {
return (
<div>
2 <F3 />
</div>
);
}
function F3() {
return (
<div>
3 <F4 />
</div>
);
}
function F4() {
return <div>4 </div>;
}
function App() {
return (
<div className="App">
<F1 />
</div>
);
}
然后重复之前的逻辑,将值通过props逐层传递<br />首先给App组件添加useState
function App() {
const num = useState(111)[0];
return (
<div className="App">
<F1 n1={num} />
</div>
);
}
之后给每个组件添加props并传递下去
function F1({ n1 }) {
return (
<div>
1 , {n1}
<F2 n2={n1} />
</div>
);
}
function F2({ n2 }) {
return (
<div>
2 ,{n2}
<F3 n3={n2} />
</div>
);
}
function F3({ n3 }) {
return (
<div>
3 ,{n3}
<F4 n4={n3} />
</div>
);
}
function F4({n4}) {
return <div>4 , {n4}</div>;
}
此时我们顺利将值111传递到了F4组件<br />
<br />在这个作用域中,F4组件只能逐层接受来自F1->F2->F3的值。
之前我们通过逐层传值的方式,将num从f1传递到了f4,但是这么麻烦,假如直接把值存放在f4的作用域外面呢
let num = 100
function f1(n1) {
console.log("f1", n1);
f2(n1);
}
function f2(n2) {
console.log("f2", n2);
f3(n2);
}
function f3(n3) {
console.log("f3", n3);
f4(n3);
}
function f4(n4) {
console.log("f4", num);
}
{
f1()
}
此时,f4可以直接访问到num<br />

此时,作为一个全局变量num,访问非常不安全
num = 55
function f4(n4) {
console.log("f4", num);
}
{
f1()
}
或者将f1在setTimeout中调用
{
setTimeout(()=>{
f1()
},1000)
num = 222
}

num作为全局变量范围太广,逻辑复杂后无法控制,很有可能拿到的不是你所想要的值,一般不推荐使用。<br />因此,我们需要一个范围大一些的局部变量。
{
let context = {
num:100
};
function f1() {
console.log("f1");
f2();
}
function f2() {
console.log("f2");
f3();
}
function f3() {
console.log("f3");
f4();
}
function f4(n4) {
console.log("f4", context.num);
}
}
在这个作用域中,都可以访问context.num,但是此时外部是无法访问这个的.
因此,在那个作用域中,我们应该给外面暴露一个set方法
window.setContext = (key,value)=>{
context[key] = value
}
{
window.setContext("num", 300);
setTimeout(() => {
window.f1();
}, 1000);
}
我们达到了f4访问context.num的作用,并且只能通过setContext方法改变值
通过闭包的方式保护了num的值。<br />react中的context也是同样造了一个局部组件能访问的变量。<br />首先声明一个context
const ThemeContext = React.createContext('light')
然后在App中调用context.Provider, 最里层组件调用Consumer
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="red">
<div className="App">
<ToolBar />
</div>
</ThemeContext.Provider>
);
}
}
function ThemeButton(props) {
return (
<ThemeContext.Consumer>
{theme => <Button theme={theme} />}
</ThemeContext.Consumer>
);
}
此时,我们顺利得让ThemeButton访问到了来自App的theme= 'red'
react context (provider和consumer)
之前,我们顺利的在consumer中拿到了provider传递过来的值。但是在consumer中不同于provider,我们需要在函数中拿到这个值。
[图片上传中...(image.png-db2c62-1601778823071-0)]
先使用babel下
React.createElement(ThemeContext.Consumer, null, function (theme) {
return React.createElement(Button, {
theme: theme
});
});
可以清晰的看出,事实上相当于创建了一个新的标签,然后将值传递给了<Button/>
function F1 () {
return 'function1'
}
<ThemeContext.Consumer>
{(theme) => <Button theme={theme} />}
F1
{F1}
<F1/>
</ThemeContext.Consumer>
function F1() {
return 'function1';
}
React.createElement(ThemeContext.Consumer, null, function (theme) {
return React.createElement(Button, {
theme: theme
});
}, "F1", F1, React.createElement(F1, null));
F1是字符串'F1', {F1}是F1函数未被调用,可通过props.children访问, <F1/>才会最终渲染。<br />事实上,consumer相当于return了props.children(),然后将其渲染在组件上。<br />我们来创建一个自己的Consumer,然后在父组件App()中调用
function Consumer(props) {
let x = 100;
let result = props.children(x);
return <div>{result}</div>;
}
function App() {
return <Consumer>{n => <div>{n}</div>}</Consumer>;
}
此时result拿到props.children(100)的值,然后挂在在<Consumer />
更新context的值
首先创建4个组件,挂载在App上
function F1() {
return (
<div className="bordered">
111
<F2 />
</div>
);
}
function F2() {
return (
<div className="bordered">
222,
<F3 />
</div>
);
}
function F3() {
return (
<div className="bordered">
333,
<F4 />
</div>
);
}
function F4() {
return <div className="bordered">444</div>;
}
class App extends React.Component {
render() {
return (
<div className="App">
<F1 />
</div>
);
}
}
.bordered {
border: 1px solid #666;
margin:5px;
}

<br />然后创建一个nContext,并将App的state中的值传递给nContext
const nContext = React.createContext(null);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
num: 100
};
}
render() {
const { num } = this.state;
return (
<div className="App">
<nContext.Provider value={num}>
<F1 />
</nContext.Provider>
</div>
);
}
}
然后将consumer包裹在F4上面,将值传给F4的props
function F3() {
return (
<div className="bordered">
333,
<nContext.Consumer>
{
value=><F4 num={value}/>
}
</nContext.Consumer>
</div>
);
}
function F4(props) {
return <div className="bordered">444,{props.num}</div>;
}
此时,F4收到了来自顶层的num=100

我们来创个update函数,然后随一个object传递给F4,这样F4就可以更新值了
function F3() {
return (
<div className="bordered">
333,
<nContext.Consumer>
{value => <F4 num={value.num} update={value.update} />}
</nContext.Consumer>
</div>
);
}
function F4(props) {
return (
<div className="bordered">
444,{props.num}
<button onClick={props.update}>click</button>
</div>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
num: 100
};
}
updateNum = () => {
this.setState({
num: 200
});
};
render() {
const { num } = this.state;
let value = {
num,
update: this.updateNum
};
return (
<div className="App">
<nContext.Provider value={value}>
<F1 />
</nContext.Provider>
</div>
);
}
}
此时,点击F4中的button,可以看到num变为200了<br />
