function renderSomething(foo) {
return <div>sth {foo}</div>
}
function Something({ foo }) {
return <div>sth {foo}</div>
}
function Component(props) {
const { foo } = props
return (
<>
{renderSomething(foo)}
<Something foo={foo} />
</>
)
}
JSX 结果为renderSomething()
and <Something />
是相同的。我想知道这两种方式之间有什么区别(例如渲染方式、行为、影响等)?
render 方法适用于什么场景(即renderSomething()
)?我可以在里面使用挂钩吗?
JSX 结果为renderSomething()
and <Something />
是相同的。
renderSomething(foo)
and <Something foo={foo} />
做完全不同的事情,但在特定的用法中,最终结果是相同的:React 创建一个 React 元素,告诉它渲染一个div
稍后(如果使用该元素)。正在做renderSomething(foo)
正在治疗renderSomething
就像一个钩子,它会影响你在它运行时如何使用它。
以下是两个主要区别:
-
With renderSomething(foo)
, your代码立即调用该函数并传入参数。和<Something foo={foo} />
,你没有打电话Something
。您要求 React 记住它,并在以后需要渲染您执行这些调用的组件时调用它。
-
因为你的代码而不是 React 调用renderSomething
,如果你在其中使用了钩子,他们会将信息放入调用组件的实例和状态信息。相反,如果Something
使用钩子,该实例和状态信息存储在组件实例中Something
itself.
(还有其他区别。你不能使用renderSomething
作为一个组件通过<renderSomething foo={foo} />
因为函数组件名称必须以大写字母开头,以区别于 HTML 元素,并且因为renderSomething
需要一个字符串参数,而不是 props 对象。)
让我们更仔细地看看其中的一些差异:
function renderSomething(foo) {
console.log(`renderSomething: Called with foo = ${foo}`);
return <div>sth {foo}</div>;
};
function Something({ foo }) {
console.log(`Something: Called with foo prop = ${foo}`);
return <div>sth {foo}</div>;
}
console.log(`Creating elements via renderSomething("x"):`);
const ex1 = renderSomething("x");
console.log(`Creating elements via <Something foo="x" />:`);
const ex2 = <Something foo="x" />;
console.log(`Done`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
请注意,代码called renderSomething
(你看到它的console.log
发生),但没有打电话Something
(你看不到它的console.log
)。这是因为上面的差异#1。关键是组件的函数只有在需要渲染时才会被调用。我们没有渲染上面的任何结果,因此该函数永远不会被调用。
第二个区别更微妙,但让我们假设两件事:
- 你的“东西”需要一个效果(也许它通过网络加载一些东西)(或者它可以是状态或引用或它使用钩子的任何其他东西),并且
- 使用它的组件(我们称之为
Example
)可能需要也可能不需要渲染它。
这很好用Something
:
const { useState, useEffect } = React;
function Something({ foo }) {
const [thing, setThing] = useState(null);
useEffect(() => {
setTimeout(() => { // Fake ajax
setThing("thing");
}, 100);
}, []);
return <div>foo = {foo}, thing = {thing}</div>;
}
function App() {
const [foo, setFoo] = useState("");
return <div>
<div>
<label>
<input type="checkbox" checked={!!foo} onChange={() => setFoo(foo => foo ? "" : "hi")} />
Toggle "foo"
</label>
{foo ? <Something foo={foo} /> : null}
</div>
</div>;
}
ReactDOM.render(<App />, document.getElementById("root"));
label {
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
但现在让我们尝试一下renderSomething
:
const { useState, useEffect } = React;
function renderSomething(foo) {
const [thing, setThing] = useState(null);
useEffect(() => {
setTimeout(() => { // Fake ajax
setThing("thing");
}, 100);
}, []);
return <div>foo = {foo}, thing = {thing}</div>;
}
function App() {
const [foo, setFoo] = useState("");
return <div>
<div>
<label>
<input type="checkbox" checked={!!foo} onChange={() => setFoo(foo => foo ? "" : "hi")} />
Toggle "foo"
</label>
{foo ? renderSomething(foo) : null}
</div>
</div>;
}
ReactDOM.render(<App />, document.getElementById("root"));
label {
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
当您勾选带有此错误的框时,它会爆炸:
Warning: React has detected a change in the order of Hooks called by App. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useState useState
2. undefined useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at App (<anonymous>:35:22)
那是因为这使得代码调用renderSomething
当我们没有在第一次渲染时调用它时。那是因为上面的#2:因为renderSomething
不是组件函数,它不会获取自己的组件实例,并且对其中的钩子的任何调用就像对父组件中的钩子的调用一样(Example
)。但函数组件有时不允许调用钩子,有时则不允许。那是因为React 依赖于调用 hooks 的顺序,并且该顺序必须是持续的让它进行钩子管理。再次,使用renderSomething
就像那样使用renderSomething
作为钩子(这正是自定义钩子的工作方式,最终调用内置钩子,然后将信息存储在父实例中)。
正如您所看到的,虽然您在示例中得到的结果是相同的,但总的来说它们是完全不同的东西。 :-)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)