React Redux应用中,如何在action方法内获取组件实例的this?
解决React类组件结合Redux时mapDispatchToProps中this为undefined的问题
我来帮你搞定这个问题!你遇到的核心痛点是mapDispatchToProps函数里的上下文和组件实例完全无关,所以这里的this肯定拿不到组件的this,自然没法调用this.setState。先分析下你的两种写法问题在哪,再给你几个合理的解决方案:
为什么你的第一种写法会报错?
在connect的第二个参数(也就是mapDispatchToProps)里,你用箭头函数定义了handleLogin:
dispatch => ({ handleLogin: e => { typeof this // "undefined" this.setState({isLogin: true}); // 这里直接报错 dispatch('LOGIN'); } })
箭头函数的this是继承自外层作用域的,而这里的外层是mapDispatchToProps函数,它的上下文并不是组件实例,所以this就是undefined,自然调用不了setState。
为什么第二种写法不合理?
你尝试把组件实例this传递给handleLogin:
<button onClick={this.props.handleLogin(this)}>Login</button>
这里有两个明显的问题:
- 每次渲染都会执行
handleLogin(this):onClick需要接收一个函数,但你现在是直接调用函数,把返回值(一个新的箭头函数)传给onClick,每次组件渲染都会创建新函数,会额外消耗性能。 - 耦合度太高:把组件实例传递给redux相关的方法,违背了redux和组件解耦的设计思想,后续维护起来会很麻烦。
正确的实现方式
方案1:把状态更新逻辑放到组件内部方法中
最合理的做法是,组件自身的UI状态(比如isLogin)由组件自己管理,redux负责全局状态(比如用户信息)。把handleLogin定义为组件的类方法(用箭头函数绑定this),在里面同时处理组件状态更新和redux动作分发:
import React, { Component } from 'react'; import { connect } from 'react-redux'; class App extends Component { state = { isLogin: false } // 用箭头函数自动绑定组件的this handleLogin = () => { // 这里能正常拿到组件实例的this,更新本地状态 this.setState({ isLogin: true }); // 调用props里的dispatch分发redux动作 this.props.dispatch({ type: 'LOGIN' }); } render() { return ( <div> <h1>{this.state.isLogin ? "Logined" : "Not logged"}</h1> <button onClick={this.handleLogin}>Login</button> </div> ) } } // connect会自动把dispatch注入到组件props中,所以第二个参数可以省略 export default connect( state => ({ user: state.user }) )(App);
方案2:结合action creator,更规范的redux写法
如果你的项目里有单独的action creator(推荐这么做,更易维护),可以在mapDispatchToProps里把action creator绑定到props,然后在组件方法里调用:
import React, { Component } from 'react'; import { connect } from 'react-redux'; // 定义action creator,单独抽离出来更清晰 const loginAction = () => ({ type: 'LOGIN' }); class App extends Component { state = { isLogin: false } handleLogin = () => { this.setState({ isLogin: true }); // 调用mapDispatch绑定好的props方法 this.props.login(); } render() { return ( <div> <h1>{this.state.isLogin ? "Logined" : "Not logged"}</h1> <button onClick={this.handleLogin}>Login</button> </div> ) } } export default connect( state => ({ user: state.user }), dispatch => ({ // 把action creator和dispatch绑定,生成可直接调用的方法 login: () => dispatch(loginAction()) }) )(App);
额外建议:考虑把UI状态移到Redux中
如果isLogin这个状态后续需要在多个组件中共享,那更推荐把它放到Redux的store里管理,这样就不用在组件里维护本地状态了,直接从props里取isLogin的值,组件会自动响应store的变化重新渲染。
内容的提问来源于stack exchange,提问作者BorodinDK
相关产品推荐
相关产品推荐

