Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React中JSX的评估顺序是什么?_Javascript_Reactjs - Fatal编程技术网

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}