我有一个父项和一个子项。
父组件具有我要访问的状态变量。
我将一个函数传递给子组件,然后在onClick上调用它。
但是,状态变量的值已过期-不是当前值。
function Parent(props) {
const [items, setItems] = useState([]);
function getItems () {
console.log(items); // always prints "[]"
}
useEffect(() => {
thirdPartyApiCall().then((fetchedItems) =>
let newItems = fetchedItems.map(item => <Child id={item.id} getItems={getItems}/>)
setItems(newItems); // populates items array. "{items}" elements correctly displayed on web page
);
}, []);
}
function Child(props) {
return <button onClick={props.getItems}>{props.id}</button>
}
答案 0 :(得分:2)
您可能想看看javascript closure的工作原理。
将给出正在发生的事情的基本概念。
useEffect
由于依赖关系只能运行一次。因此,在呈现子组件时,items
是一个空数组([]
)。您的子组件将始终具有items
的该实例,因为useEffect
不会被更新的items
调用。
希望这会有所帮助。
编辑:1
您可能希望您的父组件看起来像这样。
function Parent(props) {
const [items, setItems] = useState([]);
function getItems () {
console.log(items); // always prints "[]"
}
useEffect(() => {
thirdPartyApiCall().then((fetchedItems) =>
setItems(newItems);
);
}, []);
return newItems.map(item => <Child key={item.id} id={item.id} getItems={getItems}/>)
}
答案 1 :(得分:2)
是的,当然,单击按钮日志[]
。在此:
<Child id={item.id} getItems={getItems}/>
getItem
被评估为记录项目的函数,并且项目为[]
,因此记录了[]
。它不记录 new 项的原因是因为在编写代码时,React无法真正知道何时更新组件,因为在渲染阶段未使用任何变量。>
在Render之外使用JSX元素通常是一个坏习惯,因为它们不是具有可预测行为的真正的普通JS变量。它编译的事实更多地是 hack 而不是 features 。
将普通变量保持在该状态,并让组件执行JSX渲染。此方法与您的方法稍有不同,但按预期工作,因为单击任一按钮都会记录所有项目:
const fakeApiCall = () => Promise.resolve([
{id: 10},
{id: 20},
{id: 30},
]);
const Parent = () => {
const [items, setItems] = React.useState([]);
React.useEffect(() => {
fakeApiCall().then(setItems)
})
const getItems = () => console.log(items);
return (
<div>
{items.map(item => (
<Child
id={item.id}
key={item.id}
getItems={getItems}/>
))}
</div>
)
}
const Child = ({id, getItems}) => (<button onClick={getItems}>{id}</button>);
window.onload = () => ReactDOM.render(<Parent/>, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>