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中有额外的计算)。