Javascript 反应:更新子组件而不重新命名父组件

Javascript 反应:更新子组件而不重新命名父组件,javascript,reactjs,Javascript,Reactjs,下面是一个简单的例子: const{Component}=React 常量{render}=ReactDOM 常量标签=({text})=>( {text} ) 常量时钟=({date})=>( {date.toLocaleTimeString()} ) 类应用程序扩展组件{ 建造师(道具){ 超级(道具) 此.state={ 日期:新日期() } } componentDidMount(){ this.interval=setInterval( ()=>this.setState({date

下面是一个简单的例子:

const{Component}=React
常量{render}=ReactDOM
常量标签=({text})=>(
{text}

) 常量时钟=({date})=>( {date.toLocaleTimeString()} ) 类应用程序扩展组件{ 建造师(道具){ 超级(道具) 此.state={ 日期:新日期() } } componentDidMount(){ this.interval=setInterval( ()=>this.setState({date:new date()}), 1000 ) } 组件将卸载(){ clearInterval(this.interval) } 更新时间(){ } render(){ 返回( ) } } render(,document.getElementById('app'))

你想要什么是不可能的。要将道具传递给子组件,父组件的状态或道具应以某种方式更改。如您所知,这显然会触发重新渲染,因此所有子级都会重新渲染。要更新,您的
时钟
组件应该重新呈现,并在这种情况下卸载/重新装载,以反映DOM更改

如果你的应用程序不是那么大,也没有那么多的孩子,请不要解决这个问题,因为渲染并不昂贵。代价高昂的是组件的DOM操作。在这里,React区分真实DOM和虚拟DOM,并且不卸载/重新装载
标签
组件,即使它重新呈现。但是,如果将
标签
组件作为
PureComponent
编写,则不会重新渲染。但是对于
时钟
组件,要像这样进行更新是不可能的

class Label extends React.PureComponent {
  render() {
    console.log("rendered");
    return (<p>{this.props.text}</p>)
  }
}

const Clock = ({ date }) => (
  <div>{date.toLocaleTimeString()}</div>
)

class App extends React.Component {

  constructor() {
    super()
    this.state = {
      date: new Date()
    }
  }


  componentWillMount() {
    this.interval = setInterval(
      () => this.setState({ date: new Date() }),
      1000
    )
  }

  componentWillUnmount() {
    clearInterval(this.interval)
  }

  updateTime() {

  }

  render() {
    return (
      <div>
        <Label text="The current time is:" />
        <Clock date={this.state.date} />
      </div>
    )
  }

}
类标签扩展了React.PureComponent{
render(){
控制台日志(“呈现”);
返回({this.props.text}

) } } 常量时钟=({date})=>( {date.toLocaleTimeString()} ) 类应用程序扩展了React.Component{ 构造函数(){ 超级() 此.state={ 日期:新日期() } } 组件willmount(){ this.interval=setInterval( ()=>this.setState({date:new date()}), 1000 ) } 组件将卸载(){ clearInterval(this.interval) } 更新时间(){ } render(){ 返回( ) } }
如果要在不更新父对象的情况下更新子对象,则状态必须在子对象中。您可以将状态getter/setter从子级传递给父级,以便能够读取和更新它:

function Child({onMount}) {
  const [value, setValue] = useState(0);

  useEffect(() => {
    onMount([value, setValue]);
  }, [onMount, value]);


  return (
    <div>
      {value}
    </div>    
  );
};


function Parent() {

  let value = null;
  let setValue = null;
  
  const onChildMount = (dataFromChild) => {
    value = dataFromChild[0];
    setValue = dataFromChild[1];
  };

  // Call setValue to update child without updating parent

  return (
    <div>
      <Child onMount={onChildMount}/>
    </div>    
  );
};
函数子项({onMount}){
const[value,setValue]=useState(0);
useffect(()=>{
onMount([value,setValue]);
},[onMount,value]);
返回(
{value}
);
};
函数父函数(){
设value=null;
设setValue=null;
const onChildMount=(dataFromChild)=>{
value=dataFromChild[0];
setValue=dataFromChild[1];
};
//调用setValue更新子级而不更新父级
返回(
);
};

因为
const[value,setValue]=useState(0)位于子级中,更新值时只有子组件将重新渲染。此外,由于
父项
onChildMount
处接收
设置值
,因此,父级可以使用它们更新子级,而无需重新渲染父级。

为时钟组件提供其自身的内部状态,而不是将其作为父级的道具传递。首先,不建议在setTimeout或SetInterval中执行setState。正在调用的渲染函数与实际正在调用的DOM之间存在差异改变。react的全部要点是,它将渲染到其虚拟DOM中,然后将其与之前的进行比较,只更新所需的内容。这叫做和解。在您的示例中,标签不会重新渲染,因为它没有更改,但时钟会更改。否,默认情况下,如果父项重新渲染所有子项,则会重新渲染@ChrisCousins您可能想告诉时钟组件中不需要DOM操作。如果您希望停止对特定组件的重新渲染,有一种componentlifecycle方法
shouldcomponentupdate
,有没有办法避免通过父组件传播?我有高度嵌套结构(SVG),我知道只有某些子级会因为状态的变化而受到影响。目前我可以看到由于向下钻取而导致的可见延迟。@NikunjMadhogaria,如果我理解正确,您正在寻找
React。PureComponent
刚刚尝试快速将组件替换为PureComponent,功能停止工作。我只有一个被递归调用的组件。我的州有所有关于孩子们的详细信息,包括标签、属性等。我们想看看当切换到React时,您是否能提高性能和代码的可维护性。但是,由于这种递归,它似乎比普通HTML(它有针对不同变量的所有CSS规则)慢。我们有这样的普通CSS规则
body[x=“1”]#id1={…style 1},body[x=“2”]#id1={…style 2}
。这比React中的递归方法更快。性能是我们应用程序的重要指标之一。我们有两种解决方案:第一种是纯CSS,没有任何javascript,第二种是使用React。如果纯CSS更新需要200毫秒,React更新需要2000毫秒(因为它在javascript中有额外的计算)。