在React中更新状态后调用函数



在这个结构中:

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,但对于一个简单的问题,这仍然是一个复杂的解决方案。上面描述的解决方案应该足够了。

最新更新