Reactjs React道具状态同步会导致不必要的首次重新渲染

Reactjs React道具状态同步会导致不必要的首次重新渲染,reactjs,react-redux,react-hooks,Reactjs,React Redux,React Hooks,我想创建一个完全由其状态控制的组件人。它还应该能够将从其父组件传递到状态的props更改(firstName、lastName)同步。我有以下代码。它实现了我想要的功能,即将道具同步到状态,并在状态更改后重新渲染 然而,我注意到的一个问题是,父道具更改触发DOM更新后,会调用useEffect。因此,初始重新渲染是浪费的,因为我只希望它在调用useEffect并更改状态后重新渲染 import React,{useState, useEffect} from 'react'; const Pe

我想创建一个完全由其状态控制的组件人。它还应该能够将从其父组件传递到状态的props更改(firstName、lastName)同步。我有以下代码。它实现了我想要的功能,即将道具同步到状态,并在状态更改后重新渲染

然而,我注意到的一个问题是,父道具更改触发DOM更新后,会调用useEffect。因此,初始重新渲染是浪费的,因为我只希望它在调用useEffect并更改状态后重新渲染

import React,{useState, useEffect} from 'react';

const Person = ({firstName, lastName}) =>  {
   const [name, setName] = useState(firstName + lastName)

   useEffect(() => {
       setName(firstName + lastName);
       console.log("state changed!");
   }, [firstName, lastName])

   console.log("re-render!");
   return <div>render {name}</div>;
}

export default Person;

您需要在useEffect中添加一个条件。比如:

const [didUpdate, setDidUpdate] = useState(false);

useEffect(() => {
  if(didUpdate){
    setName(firstName + lastName);
    console.log('state changed!');
  } else {
    setDidUpdate(true);
  }
}, [firstName, lastName]);
这里它重现了componentDidUpdate()行为

在第一次渲染时,组件被挂载,didUpdate被初始化为false,因此效果只会在下次更新时将其设置为true


请注意,使用道具初始化的状态(useState)在道具更改时不会更新。

根据

传递给useEffect的函数将在渲染提交到屏幕后运行

为了避免由副作用引起的bug

我想你简化了你的例子,但是你应该知道无条件地将道具复制到state是一种反模式

相反,你应该直接使用道具:

const Person = ({firstName, lastName}) => (
  <div>render {firstName + lastName}</div>;
);
constperson=({firstName,lastName})=>(
呈现{firstName+lastName};
);

如果在第一次装载时未执行useEffect代码,对您是否有效?问题更多的是如何防止来自其父级的道具更改导致重新渲染。最终目标是使道具更改只调用useEffect,后者根据道具更新状态,而不是重新呈现组件。只有在状态更改后才会触发重新渲染Hanks,由父道具更改引起的第一次重新渲染不会仍然发生吗?您必须对此进行测试,这是一个好问题,但由于您的父道具正在重新渲染,我假设子道具也在重新渲染。因此,它将为您的孩子生成第一次渲染,因此不会触发效果。让我知道当你测试它时,我很好奇:)看起来我错了。这里有人说,如果父对象更新,您的子对象将不会自动重新渲染。因此,它不会改变这样一个事实,即如果父级渲染,子级将保持原样,并使用
didUpdate=true
(因为它们之前已经渲染过一次)该链接中的问题是,当道具没有改变时,子组件何时被重新呈现。我刚才在谈论他的答案的开头,他解释了呈现父组件如何影响子组件。我的示例过于简化。我在组件中有逻辑来更新状态而不影响其父级,但也希望接受来自父级的更改您永远不会从子级更新父级(React数据流是单向的)。你能发布完整的组件吗?我的组件很复杂。您可以将
return render{name}
替换为
return setName(e.target.value)}>
。再举一个例子。因此,组件的状态将从其父组件传递的道具或输入上的交互更新。来自父级的道具不应该重新呈现组件,而应该只更新状态好的,所以在我看来,这里的错误在于,您都使用父级的道具和本地状态来管理
名称
。这里,
Person
il没有完全控制,因为它有一个本地状态。完全受控组件是仅使用父级道具进行更新的组件。如果您想要一个完全受控的组件,您应该做的是:const Person=({name,onChange})=>{…return();}并使用onChange更新父状态,在那里存储传递给
Person的
name
const Person = ({firstName, lastName}) => (
  <div>render {firstName + lastName}</div>;
);