为什么要创建上下文而不是仅仅导出对象?
Why create contexts instead of just exporting objects?
所以我想避免 props 的深度嵌套,我开始使用 React context 来做到这一点,但后来我想到了 "why don't I just export objects instead?"
例如,而不是写:
const handleClick: = event => {
event.preventDefault();
doSomething();
};
const calcPrice = (quantity) = {
return quantity * 100
};
export const ComponentContext = createContext({});
export const ParentComponent = () => {
return (
<ComponentContext.Provider value={{ handleClick, calcPrice }}>
<ChildComponent quantity={12} />
</ComponentContext.Provider>
}
并将其导入为:
export const ChildComponent = (quantity) = {
const { handleClick, calcPrice } = useContext(ComponentContext);
const totalPrice = calcPrice(quantity);
return <button onClick={handleClick}>Total is ${totalPrice}</button>
}
我可以简单地写成:
const handleClick: = event => {
event.preventDefault();
doSomething();
};
const calcPrice = (quantity) = {
return quantity * 100
};
export const componentProps = { handleClick, calcPrice };
export const ParentComponent = () => {
return <ChildComponent quantity={12} />
}
并将其导入为:
const { handleSignUpClick, calcPrice } = componentProps;
export const ChildComponent = (quantity) = {
const totalPrice = calcPrice(quantity);
return <button onClick={handleClick}>Total is ${totalPrice}</button>
}
使用上下文而不是函数有什么好处?
在您的示例中,您似乎只是导出了一些辅助函数。在那个用例中,导出对象(具有这些函数)和使用 useContext()
挂钩之间可能没有任何区别。
https://reactjs.org/docs/hooks-reference.html#usecontext
但是,从 React DOCs(上面的 link),我们得到:
A component calling useContext will always re-render when the context value changes. If re-rendering the component is expensive, you can optimize it by using memoization.
您将如何使用导出的对象实现(re-render 的消费者)?
从父级的角度来看,当您使用不同的 props
对象渲染它时,所有可能触发子组件 re-render 的情况。你导出的位于组件函数之外的东西(因为你不能导出局部函数变量和 'methods')如何能够更改在组件函数范围内创建的 props
对象?
TLDR:
基本区别在于您不能使用导出的对象导致 re-render 个消费者子级。至少不是没有陷入一个完整的 React anti-pattern.
假设您有一个 ParentComponent
渲染 两个昂贵的子组件,您想要对其进行优化。 为此您将使用 React.memo()
所以你只有 re-render 那些子组件,如果它们 props
改变了。
使用上下文的会re-render,因为上下文属性变了,但是使用导出变量的不会re-render,因为所有这改变了 React 之外的生活。
沙盒示例:
https://vq30v.codesandbox.io/
ParentComponent.js
import React, { useState } from "react";
import SomeContext from "./SomeContext";
import ExpensiveChildComponent from "./ExpensiveChildComponent";
import ExpensiveChildComponentExport from "./ExpensiveChildComponentExport";
let count = null; // VARIABLE THAT WILL BE EXPORTED
console.log("Outside ParentComponent...");
function ParentComponent() {
const [myState, setMyState] = useState(0);
console.log("Rendering Parent Component...");
count = myState; // UPDATING THE EXPORTED VARIABLE
function handleClick() {
setMyState(prevState => prevState + 1);
}
// SETTING UP CONTEXT PROVIDER
return (
<div>
<SomeContext.Provider value={myState}>
<button onClick={handleClick}>Count</button>
<h3>Uses Context</h3>
<ExpensiveChildComponent />
<h3>Uses Exported Object</h3>
<ExpensiveChildComponentExport />
</SomeContext.Provider>
</div>
);
}
console.log("After ParentComponent declaration...");
export { ParentComponent, count }; // EXPORTING COMPONENT AND VARIABLE
ExpensiveChildComponent.js(使用上下文)
import React, { useContext } from "react";
import SomeContext from "./SomeContext";
// REACT MEMO WILL ONLY UPDATE IF PROPS OR CONTEXT HAS CHANGED
const ExpensiveChildComponent = React.memo(function ExpensiveChildComponent() {
console.log("Rendering ExpensiveChildComponent...");
const context = useContext(SomeContext);
return <div>{context}</div>;
});
export default ExpensiveChildComponent;
ExpensiveChildComponentExport.js(使用导出的 属性)
import React from "react";
import { count } from "./ParentComponent"; // IMPORTING THE EXPORTED VARIABLE
console.log("Outside ExpensiveChildComponentExport...");
// REACT MEMO WILL ONLY UPDATE IF PROPS OR CONTEXT HAS CHANGED (AND BOTH ARE NOT BEING USED)
const ExpensiveChildComponentExport = React.memo(
function ChildComponentExport() {
console.log("Rendering ExpensiveChildComponentExport...");
return (
<React.Fragment>
<div>{count}</div>
</React.Fragment>
);
}
);
export default ExpensiveChildComponentExport;
结果:
注意:
如果您从 ExpensiveChildComponentExport
中删除 React.memo
,它将 re-render,因为 React 在每次渲染时都会创建一个新的 props
对象(它将是一个空对象,但每次都会有所不同)。这就是我添加 React.memo()
的原因,因为它将对 props
对象执行浅比较。因此,我可以说明 useContext
具有的行为,而单纯的导出对象则没有。
所以我想避免 props 的深度嵌套,我开始使用 React context 来做到这一点,但后来我想到了 "why don't I just export objects instead?"
例如,而不是写:
const handleClick: = event => {
event.preventDefault();
doSomething();
};
const calcPrice = (quantity) = {
return quantity * 100
};
export const ComponentContext = createContext({});
export const ParentComponent = () => {
return (
<ComponentContext.Provider value={{ handleClick, calcPrice }}>
<ChildComponent quantity={12} />
</ComponentContext.Provider>
}
并将其导入为:
export const ChildComponent = (quantity) = {
const { handleClick, calcPrice } = useContext(ComponentContext);
const totalPrice = calcPrice(quantity);
return <button onClick={handleClick}>Total is ${totalPrice}</button>
}
我可以简单地写成:
const handleClick: = event => {
event.preventDefault();
doSomething();
};
const calcPrice = (quantity) = {
return quantity * 100
};
export const componentProps = { handleClick, calcPrice };
export const ParentComponent = () => {
return <ChildComponent quantity={12} />
}
并将其导入为:
const { handleSignUpClick, calcPrice } = componentProps;
export const ChildComponent = (quantity) = {
const totalPrice = calcPrice(quantity);
return <button onClick={handleClick}>Total is ${totalPrice}</button>
}
使用上下文而不是函数有什么好处?
在您的示例中,您似乎只是导出了一些辅助函数。在那个用例中,导出对象(具有这些函数)和使用 useContext()
挂钩之间可能没有任何区别。
https://reactjs.org/docs/hooks-reference.html#usecontext
但是,从 React DOCs(上面的 link),我们得到:
A component calling useContext will always re-render when the context value changes. If re-rendering the component is expensive, you can optimize it by using memoization.
您将如何使用导出的对象实现(re-render 的消费者)?
从父级的角度来看,当您使用不同的 props
对象渲染它时,所有可能触发子组件 re-render 的情况。你导出的位于组件函数之外的东西(因为你不能导出局部函数变量和 'methods')如何能够更改在组件函数范围内创建的 props
对象?
TLDR:
基本区别在于您不能使用导出的对象导致 re-render 个消费者子级。至少不是没有陷入一个完整的 React anti-pattern.
假设您有一个 ParentComponent
渲染 两个昂贵的子组件,您想要对其进行优化。 为此您将使用 React.memo()
所以你只有 re-render 那些子组件,如果它们 props
改变了。
使用上下文的会re-render,因为上下文属性变了,但是使用导出变量的不会re-render,因为所有这改变了 React 之外的生活。
沙盒示例: https://vq30v.codesandbox.io/
ParentComponent.js
import React, { useState } from "react";
import SomeContext from "./SomeContext";
import ExpensiveChildComponent from "./ExpensiveChildComponent";
import ExpensiveChildComponentExport from "./ExpensiveChildComponentExport";
let count = null; // VARIABLE THAT WILL BE EXPORTED
console.log("Outside ParentComponent...");
function ParentComponent() {
const [myState, setMyState] = useState(0);
console.log("Rendering Parent Component...");
count = myState; // UPDATING THE EXPORTED VARIABLE
function handleClick() {
setMyState(prevState => prevState + 1);
}
// SETTING UP CONTEXT PROVIDER
return (
<div>
<SomeContext.Provider value={myState}>
<button onClick={handleClick}>Count</button>
<h3>Uses Context</h3>
<ExpensiveChildComponent />
<h3>Uses Exported Object</h3>
<ExpensiveChildComponentExport />
</SomeContext.Provider>
</div>
);
}
console.log("After ParentComponent declaration...");
export { ParentComponent, count }; // EXPORTING COMPONENT AND VARIABLE
ExpensiveChildComponent.js(使用上下文)
import React, { useContext } from "react";
import SomeContext from "./SomeContext";
// REACT MEMO WILL ONLY UPDATE IF PROPS OR CONTEXT HAS CHANGED
const ExpensiveChildComponent = React.memo(function ExpensiveChildComponent() {
console.log("Rendering ExpensiveChildComponent...");
const context = useContext(SomeContext);
return <div>{context}</div>;
});
export default ExpensiveChildComponent;
ExpensiveChildComponentExport.js(使用导出的 属性)
import React from "react";
import { count } from "./ParentComponent"; // IMPORTING THE EXPORTED VARIABLE
console.log("Outside ExpensiveChildComponentExport...");
// REACT MEMO WILL ONLY UPDATE IF PROPS OR CONTEXT HAS CHANGED (AND BOTH ARE NOT BEING USED)
const ExpensiveChildComponentExport = React.memo(
function ChildComponentExport() {
console.log("Rendering ExpensiveChildComponentExport...");
return (
<React.Fragment>
<div>{count}</div>
</React.Fragment>
);
}
);
export default ExpensiveChildComponentExport;
结果:
注意:
如果您从 ExpensiveChildComponentExport
中删除 React.memo
,它将 re-render,因为 React 在每次渲染时都会创建一个新的 props
对象(它将是一个空对象,但每次都会有所不同)。这就是我添加 React.memo()
的原因,因为它将对 props
对象执行浅比较。因此,我可以说明 useContext
具有的行为,而单纯的导出对象则没有。