react 获取子组件的 state (转发)
原文:How to access childs state from parent component in React
Are you seeking how to access a child state from a parent component?
This is the article you’ve been waiting for!
The answer: Use a callback function
The most common method is to make a callback function that the child component will trigger and toss the state values upward.
Let’s take a look at a couple methods.
Get state value onClick event
One method is to update state, and when a click happens, use a callback function that gives the parent component the values.
Here’s an article that covers this method more in detail, “How to get form data on submit in ReactJS“.
Get state value on onChange event
The method above covers how to pass the child state over a click event.
But what about when input field changes?
We sure can do that as well! Let’s take a look at how.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class ChildComponent extends React.Component { state = { username: '' , password: '' , } handleChange = e => { this .setState({ [e.target.name]: e.target.value }, () => { if ( this .props.onChange) { this .props.onChange( this .state); } }) }; render() { return ( <> <div> <div>Username:</div> <input name= "username" onChange={ this .handleChange} /> </div> <br /> <div> <div>Password:</div> <input name= "password" onChange={ this .handleChange} /> </div> <br /> <div> <button onClick={ this .handleSubmit}>Submit</button> </div> </> ); } } |
Let’s take a look at the the code snippet that handles React state update and returns the new state object to the parent component.
1 2 3 4 5 6 7 8 9 10 11 12 | state = { username: '' , password: '' , } handleChange = e => { this .setState({ [e.target.name]: e.target.value }, () => { if ( this .props.onChange) { this .props.onChange( this .state); } }) }; |
In the handleChange()
method, I’m calling this.setState()
, and updating the component state object with the new values.
In this.setState()
, i’m also passing a function as a second parameter. That function gets called once the React state object has been modified.
In that callback function, I’m checking if the React parent component provided a prop called onChange()
, and if so, pass the updated child component state object.
Let’s see how the code looks like in the parent component:
1 2 3 4 5 6 | function App() { const eventhandler = data => console.log(data) return <ChildComponent onChange={eventhandler} />; } |
Fairly simple. As I’m typing I see a log as such:
1 2 3 4 | Object {username: "a" , password: "" } Object {username: "a" , password: "s" } Object {username: "a" , password: "ss" } Object {username: "a" , password: "sss" } |
Is there a more recommended way after React state has changed?
Yes! Let’s take a look at React's componentDidUpdate
lifecycle.
Get state value on React componentDidUpdate
If you’re curious to read up on how React componentDidUpdate
works, check out this article, “How does React componentDidUpdate work“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class ChildComponent extends React.Component { state = { username: '' , password: '' , } handleChange = e => this .setState({ [e.target.name]: e.target.value }); componentDidUpdate() { if ( this .props.onChange) { this .props.onChange( this .state); } } render() { return ( <> <div> <div>Username:</div> <input name= "username" onChange={ this .handleChange} /> </div> <br /> <div> <div>Password:</div> <input name= "password" onChange={ this .handleChange} /> </div> <br /> <div> <button onClick={ this .handleSubmit}>Submit</button> </div> </> ); } } |
The only change here is to move the callback function in this.setState()
onto the componentDidUpdate
lifecycle.
This may be a more beneficial approach because:
- You have access to previous props and state for comparison
- It’s better suited when React performs batching
- More consistent code logic
In the example above I demonstrated a class component, what if you’re using a functional component?
You can use the React useEffect hook
to emulate componentDidUpdate
.
Get state value on React useEffect hook
Here’s how we can pass the state to the parent component with the React useEffect hook
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function ChildComponent(props) { const [formData, setFormData] = React.useState({ username: '' , password: '' }); const handleChange = e => setFormData({ ...formData, [e.target.name]: e.target.value }); React.useEffect(() => { if (props.onChange) { props.onChange(formData) } }, [formData.username, formData.password]) return ( <> <div> <div>Username:</div> <input name= "username" onChange={handleChange} /> </div> <br /> <div> <div>Password:</div> <input name= "password" onChange={handleChange} /> </div> <br /> </> ); } |
Get state with React useRef or createRef
This certainly NOT recommended, but it’s a nice to know.
Before you get the reference from a component, make sure your child component is a class type.
If you try to get the reference from a function component, your code will break.
Type '{ ref: MutableRefObject<any>; }' is not assignable to type 'IntrinsicAttributes & { children?: ReactNode; }'.
Property 'ref' does not exist on type 'IntrinsicAttributes & { children?: ReactNode; }'
All this really means, is that functional components don’t have an instance. They’re stateless.
But if your child component is a class type, then this is how you get the state from it with React useRef hook
or createRef()
.
But if your child component is a class type, then this is how you get the state from it with React useRef hook
or createRef()
.
1 2 3 4 5 6 7 8 9 10 | function App() { const childCompRef = React.useRef( null ); React.useLayoutEffect(() => { console.log(childCompRef) }, []) return <ChildComponent ref={childCompRef} />; } |
And the output on the console should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 | current: ChildComponent props: Object context: Object refs: Object updater: Object state: Object username: "" password: "" handleChange: function () {} _reactInternalFiber: FiberNode _reactInternalInstance: Object <constructor>: "ChildComponent" |
You can then go through the object reference path to get to the state object
1 | childCompRef.current.state // {username: "", password: ""} |
The only caveat here is that this only works for the initial state. If your child component state is updated, the reference variable will not be updated with the new values.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?