我有一个组件,我想在渲染之前通过一个非反应动画库运行。这使我无法使用标准的隐藏/显示逻辑的标准路线。我最初尝试使用ReactDOM。createPortal,但它根本不呈现组件。使用ReactDOM。渲染,我已经让元素在动画完成后正确渲染并且我能够成功地将更改传播到"父元素";状态,但状态更改不会向下传播到"子"。下面是我的代码:
Html
<div id="root"></div>
<div id="childPlaceholder"></div>
Javascript
import './App.css';
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
function App() {
const [data, updateData] = useState(0)
function add(val) {
console.log("add");
updateData(val);
}
function renderSubpage() {
let $el = document.getElementById("childPlaceholder");
// NonReactAnimationLibrary.ShowContainer($el);
ReactDOM.render(<Child number={data} add={add} />, $el);
// ReactDOM.createPortal(<Child number={data} add={add} />, $el);
}
return ( <>
<button onClick={renderSubpage}>
add child
</button>
<div> data: {data}</div>
</>
);
}
function Child(props) {
return <>
<button onClick={()=>{props.add(props.number + 1)}}>add number</button>
<div>child {props.number}</div>
</>
}
export default App;
有可能在反应中做到这一点吗?
更新1:
所以我已经根据oliver的响应更新了代码,它使用门户正确呈现,但是子组件仍然不呈现父组件
中的状态更改const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");
function Child(args) {
return ReactDOM.createPortal(<>
<div>child: {args.number}</div>
<button onClick={()=>{args.add(args.number+1)}}>Increment base number</button>
</>, childRoot);
}
export default class App extends React.Component {
constructor() {
super();
this.state = { data: 0, number:0 };
}
add = (val)=> {
this.setState({
...this.state,
number: val
});
}
addChild = () => {
this.setState(prevState => ({data: prevState.data + 1}));
}
render() {
const children = Array(this.state.data)
.fill()
.map((_, i) => <Child key={i} number={0} add={this.add}/>);
return (
<div>
<button onClick={this.addChild}>
add child
</button>
<div> data: {this.state.data}</div>
{children}
</div>
);
}
}
ReactDOM.render(<App/>, root);
更新2:
罪犯被找到了。改变了
number={0}
number={this.state.number}
,它工作
React.createPortal
必须在渲染方法中使用(我使用类组件,因为我不能在SO示例中使用钩子,你当然可以使用功能组件)。
您可以像下面这样在App
组件或Child
组件中使用它:
const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");
function Child({number}) {
return <div>child {number}</div>;
}
class App extends React.Component {
constructor() {
super();
this.state = { data: 0 };
}
addChild = () => {
this.setState(prevState => ({data: prevState.data + 1}));
}
render() {
const children = Array(this.state.data)
.fill()
.map((_, i) => <Child key={i} number={i} />);
return (
<div>
<button onClick={this.addChild}>add child</button>
<div> data: {this.state.data}</div>
{ReactDOM.createPortal(children, childRoot)}
</div>
);
}
}
ReactDOM.render(<App/>, root);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<div id="childPlaceholder"></div>