1. 四层函数传递值
- 原生JS的做法:
function f1(n1) {
console.log(1, n1); // , 是分隔符哦,不会打印出来
f2(n1);
}
function f2(n2) {
console.log(2, n2);
f3(n2);
}
function f3(n3) {
console.log(3, n3);
f4(n3);
}
function f4(n4) {
console.log(4, n4);
}
{
let n = 100;
f1(n);
console.log("done"); // f1 全部四层函数执行完毕后才打印 done
}
//1 100
//2 100
//3 100
//4 100
//done
- 使用 React 改写
function F1(props) {
return(
<div>
1, {props.n1}
<F2 n2={props.n1} />
</div>
)
}
function F2(props) {
return(
<div>
2, {props.n2}
<F3 n3={props.n2} />
</div>
)
}
function F3(props) {
return(
<div>
3, {props.n3}
<F4 n4={props.n3} />
</div>
)
}
function F4(props) {
return(
<div>
4, {props.n4}
</div>
)
}
class App extends React.Component {
constructor(){
super()
this.state ={
n: 100
}
}
render(){
return(
<div>
<F1 n1={this.state.n}/>
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector('#app'))
能否直接将 n
传到 f4
,而不需要通过 f1
、f2
、 f3
层层传递?
2. 你说使用全局变量?
- 使用全局变量不安全,随处可改
全局变量慎用 - 做个约定:传一个局部的全局变量
① ES5 里造一个局部变量,要用立即执行函数!function() {}()
② ES6里造局部变量:{ }
改写原生JS代码:
用let
声明了一个局部的全局变量
{
let context= {} //context 就是局部的全局变量,其他地方访问不了(闭包)
window.setContext = function(key,value){
context[key] = value
}
window.f1 = function f1() {
console.log(1)
f2()
}
function f2() {
console.log(2)
f3()
}
function f3() {
console.log(3)
f4()
}
function f4() {
console.log(4, context['n'])
}
}
window.setContext('n', 100) //设置context
window.f1()
- 在 React 中使用
Context
API
看看官方文档对 Context
的定义:
在一个典型的 React 应用中,数据是通过
props
属性由上向下(由父及子)的进行传递的,但这对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI主题),这是应用程序中许多组件都所需要的。Context
提供了一种在组件之间共享此类值的方式,而不必通过组件树的每个层级显式地传递props
。
React改写的版本:
const nContext = React.createContext();
function F1(props) {
return (
<div className="bordered">
1
<F2 />
</div>
);
}
function F2(props) {
return (
<div className="bordered">
2
<F3 />
</div>
);
}
function F3(props) {
return (
<div className="bordered">
3
<nContext.Consumer>
{x => <F4 n4={x} />}
</nContext.Consumer>
</div>
);
}
function F4(props) {
return <div className="bordered">4, {props.n4} </div>;
}
class App extends React.Component {
render() {
return (
<div>
<nContext.Provider value="100">
<F1 />
</nContext.Provider>
</div>
);
}
}
3. 标签里居然可以传函数
注意: 你写的代码不是 html
<div className="bordered">
3333
<nContext.Consumer>
{(x) => <F4 n4={x}/>}
</nContext.Consumer>
</div>
babel在线转换后,代码是这样的:
React.createElement("div", { className: "bordered" },
"3333",
React.createElement(nContext.Consumer, null, function (x) {
return React.createElement(F4, {
n4: x
});
})
);
这才是你写的代码的真实模样 : )
解释一下标签可以传函数:
function Consumer(props) {
let x = 100;
let result = props.children(x);
return <div>{result}</div>;
}
function F4(n) {
return <div>{n}</div>;
}
function App() {
return (
<div className="App">
<Consumer>
{F4}
</Consumer>
</div>
);
}
-
{F4}
在<Consumer>
里, 其实返回的是F4
这个函数。(不是函数运行后的结果) - 在组件
Consumer
里,可以用props.children
获取 这个函数 - 在
Consumer
函数里,执行props.children(x)
,同时传入函数x
,返回的是F4
函数的返回值。
简化代码:
function Consumer(props) {
let x = 100;
let result = props.children(x);
return <div>{result}</div>;
}
function App() {
return <Consumer>{n => <div>{n}</div>}</Consumer>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
4. 更新 Context 里的值
如何让 F4
自己来改变这个值 => 把值和方法都放到 this.state
里面,然后传给nContext.Provider
的 value
。
const nContext = React.createContext();
function F1(props) {
return (
<div className="bordered">
1
<F2 />
</div>
);
}
function F2(props) {
return (
<div className="bordered">
2
<F3 />
</div>
);
}
function F3(props) {
return (
<div className="bordered">
3
<nContext.Consumer>
{x => <F4 n4={x.n} setN={x.setN} />}
</nContext.Consumer>
</div>
);
}
function F4(props) {
return (
<div className="bordered">
4, {props.n4}
<button onClick={props.setN}>change</button>
</div>
);
}
class App extends React.Component {
constructor() {
super();
this.state = {
x: {
n: 100,
setN: () => {
this.setState({
x: {
...this.state.x, //es6 扩展运算符语法,除了n之外的setN也要保留下来
n: this.state.x.n - 1
}
});
}
}
};
}
render() {
return (
<div>
<nContext.Provider value={this.state.x}>
<F1 />
</nContext.Provider>
</div>
);
}
}
结合我上篇文章的 React入门 6:Redux 是什么 来看,有没觉得 Context
很像 React-Redux 里的 <Provider>
,: )