Javascript React中JSX的评估顺序是什么?
假设我有以下组件:Javascript React中JSX的评估顺序是什么?,javascript,reactjs,Javascript,Reactjs,假设我有以下组件: const Cell = (props) => { const { cellData } = props; console.log("--START--") console.log(cellData); console.log("--END--") return <div>cellData</div>; }; const Col = (props) => {
const Cell = (props) => {
const { cellData } = props;
console.log("--START--")
console.log(cellData);
console.log("--END--")
return <div>cellData</div>;
};
const Col = (props) => {
const { cell } = props;
console.log(cell);
return (<div> </div>);
}
const单元格=(道具)=>{
const{cellData}=props;
console.log(“--START-->”)
console.log(cellData);
console.log(“--END-->”)
返回数据;
};
常量列=(道具)=>{
const{cell}=props;
控制台日志(单元);
返回();
}
像这样做
const col = (<Col
cell={<Cell />}
/>);
const content = (
<div>
{col}
</div>
);
const col=();
常量内容=(
{col}
);
似乎先在Col中运行代码。但是,如果props只是一个函数参数,它不应该首先运行传入的
部分吗?,因为这是一件值得测试的小事。你所看到的和你所问的是同一过程的两个方面
问题
当您登录到功能组件的主体时,这是作为副作用完成的
功能组件的函数体本质上等同于基于类的组件的render
方法。换句话说,整个函数就是“render”方法。React“渲染”每个组件,作为协调过程的一部分,以计算从任何一个渲染周期到下一个渲染周期的差异。还请注意,“render”函数被视为纯函数,没有任何副作用,如控制台日志记录或任何其他异步行为
您询问“评估顺序”,您认为应该看到的是“渲染顺序”。换句话说,React必须以深度优先遍历的方式从上到下计算组件树,但它从下到上呈现给DOM。它需要完全处理任何子树中的所有子树以计算该子树的差异
在React中,我们通常不关心任何事情,直到组件被安装并可用,因为组件可以“使用DOM、运行副作用和计划更新”。这就是为什么安装顺序通常比评估顺序更重要。React可以“暂停、中止或重新启动”评估
使用提供的代码,在将组件呈现到DOM中时修改为控制台日志:
const Cell = ({ cellData }) => {
useEffect(() => {
console.log("Cell MOUNTED");
console.log("--START--");
console.log({ cellData });
console.log("--END--");
}, []);
return <div>{cellData}</div>;
};
const Col = ({ cell }) => {
useEffect(() => {
console.log("Col MOUNTED", { cell });
}, []);
return <div>Col: {cell}</div>;
};
export default function App() {
const col = <Col cell={<Cell cellData="hello world!" />} />;
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div>{col}</div>
</div>
);
}
渲染组件的一部分是完全渲染其子组件的子树。所有的子项都需要先渲染。它不可能以任何其他方式或以任何其他顺序工作。如果React没有这种确定的顺序,那么就不可能将渲染的DOM结果从一个渲染周期区分到下一个渲染周期。只需给出一个简单的答案: 似乎先在Col中运行代码。但是如果props只是一个函数参数,它不应该首先运行传入的部分吗 答案是否定的 考虑一下:React无法知道单元格道具的
Col
功能。如果Col
的实现如下所示:
const Col=({cell})=>{
const[canRender,setCanRender]=useState(false);
useffect(()=>{
const timer=setTimeout(()=>setCanRender(true),1000:
return()=>clearTimeout(计时器);
},[]);
返回{canRender?单元格:null}
}
React会浪费时间和精力调用单元格
,而Col
甚至不会立即(或可能永远)渲染它
只是想在这次行动中提出一个很好的观点:
React仅在组件从其直接父级渲染返回后才对其进行评估(例如调用)。我认为组件函数体中糟糕的控制台日志记录可能会让您感到困惑(它们都应该记录在
useffect
中),但react组件需要先渲染出其子级,然后才能将其视为“渲染”。这可能有助于解释原因。Drew Reese是对的,但我相信混淆源于这样一个事实:
根本没有调用render。React在元素树中导航时调用render。所有子项都需要先渲染
-您得出了错误的结论,因为您使用的是useEffect代码>-,显然必须先渲染父对象,然后才能渲染子对象,因为父对象可能会选择不渲染子对象-如果父对象无论如何都不渲染子对象,则框架没有必要渲染子对象。不过,我觉得我可能误解了您的解释中的某些内容。@Adam请查看并注意该函数功能组件的主体是“render”方法,在“render阶段”中调用render。还要注意的是,这应该是一个没有副作用的纯函数,就像控制台记录任何东西一样。“render阶段”经常与正在呈现的组件合并,即在“提交阶段”将其提交到DOM时,其中调用了componentDidMount
或初始的useEffect
回调。@没错,React首先开始处理父对象OFC,因为它需要知道它必须在这些子对象上递归哪些子对象,但同样,这是在“渲染阶段”而不是在“提交阶段”。“评估”顺序为自上而下,而“渲染”顺序为“/安装顺序是自底向上的。如果更容易的话,请将React渲染视为深度优先遍历。在组件安装并可用之前,我们通常不关心任何事情。我理解您现在所说的,但至少对我来说,您所描述的并不能回答OPs问题。
Cell MOUNTED
--START--
{cellData: "hello world!"}
--END--
Col MOUNTED
{cell: Object}