在这个结构中:
export const Parent = () => {
function updateFn(e) {
e.preventDefault()
// do some action with the updated counter
}
return (
<Child updateFn={updateFn} />
)
}
export const Child = (props) => {
const [counter, setCounter] = useState(0)
function updateCounter() {
setCounter(1)
}
return (
<button onClick={updateCounter}></button>
)
}
在counter
更新后,用相同的点击从<Child>
中调用updateFn()
的最佳方法是什么?我需要这个,因为我正在使用updateFn()
中更新的计数器的值。
我在<Child>
中尝试了useEffect
:
useEffect(() => {
props.updateFn()
}, [counter])
,但问题是,首先,它试图调用函数立即挂载,这是不好的,因为计数器没有更新,其次,最重要的是,我得到一个错误Cannot read property 'preventDefault' of undefined
-如果我注释出preventDefault()
,将导致刷新,这也不好。作为一个侧面问题,我怎么能从<Child>
内调用这个,但也保持preventDefault()
的行为?如果我在onClick事件中调用它,没有括号()
,preventDefault()
将工作。
我找到的解决方案是:
<div onMouseOver={() => setCounter(1)}>
<button onClick={props.updateFn} />
</div>
虽然这是有效的,但我认为这不是一个很好的方法,我想学习正确的方法。
谢谢!
最后,我试着按照评论中的建议使用useReducer()
,我正在用更多的细节更新问题,几乎改变了它的整个意义和结构。
我想要实现的是使用useReducer()
从包装器组件控制弹出窗口,并发送我想要在弹出窗口上显示的数据,调用调度并使用该包装器的子负载。
在这个弹出窗口上,我通常有一个按钮需要做不同的事情取决于打开弹出窗口的子窗口。理想情况下,当我从子窗口打开弹出窗口时,我也想发送不同的函数。
到目前为止,减速器的初始状态看起来像以下几行:
const [userActions, dispatch] = useReducer(reducer, [
{
popup: false,
valueToUseIn_someFn: "",
action: new Function()
}
]);
获取数据的第一个案例看起来像这样:
case "get-data":
return {
...userActions,
...action.payload,
}
我在子元素中设置动作并打开弹出窗口,像
props.dispatch({
type: "get-data",
payload: {
popup: true,
valueToUseIn_someFn: someValue,
action: function() {
return someFn()
}
}
})
一旦弹出窗口打开,当按下确认按钮时,我调用先前设置的函数,如:
case "do-the-action":
userActions.action()
这正在工作,当我按下确认时,someFn()
正在被调用。
someFn()
看起来像:
console.log(props.userActions.valueToUseIn_someFn)
function someFn() {
console.log(props.userActions.valueToUseIn_someFn)
}
但问题是,每次我按下确认,在someFn()
的日志显示以前设置的状态:
如果首先是someValue = 1
,这将是:
//inside the child of the wrapper
console.log(props.userActions.valueToUseIn_someFn) //returns1
function someFn() {
console.log(props.userActions.valueToUseIn_someFn) //returns undefined
}
如果第二个someValue = 2
这将是:
//inside the child of the wrapper
console.log(props.userActions.valueToUseIn_someFn) //returns 2
function someFn() {
console.log(props.userActions.valueToUseIn_someFn) //returns 1
}
我还记录了userAction
对象被孩子更新后,似乎我需要的所有数据都更新和可用。只是someFn()
不采用当前状态,只采用先前设置的状态,以此类推。
所以现在我比以往任何时候都更加困惑,我真的很想知道为什么会发生这种情况,如何修复,这种方法有什么问题,以及这样做的最佳实践。
再次感谢!
您可以在updateCounter
函数中这样做:
function updateCounter(e) {
setCounter(1);
props.updateFn(e);
}
此外,您可以在updateCounter
函数中获取onClick
的事件参数并将其传递给updateFn
,以便能够在该事件上调用preventDefault
。
在useEffect
中使用counter
作为依赖项调用它确实会在第一次渲染时执行它。您可以添加一个额外的状态变量来跟踪它是否是第一次单击,并根据它调用updateFn
,但对于一个简单的问题,这仍然是一个复杂的解决方案。上面描述的解决方案应该足够了。