React 16升级:用getDerivedStateFromProps替代componentWillReceiveProps不触发问题
看起来你遇到的问题很典型——很多人在从componentWillReceiveProps迁移到getDerivedStateFromProps时都会踩这个坑。我帮你分析下最可能的原因和解决办法:
1. 最常见的错误:忘记给getDerivedStateFromProps加static关键字
getDerivedStateFromProps是类的静态方法,必须用static修饰,React才能识别并在合适的时机调用它。如果像写实例方法那样定义它,React根本不会触发这个方法。
你之前的componentWillReceiveProps是实例方法所以能正常工作,但getDerivedStateFromProps必须写成静态方法:
@connect(state=> ({user: state.user, global: state.global}), {loginUser}) class LoginFormContainer extends React.Component { constructor() { super() this.state = { email: '', password: '', isAuthenticated: false } } // 正确写法:必须加static! static getDerivedStateFromProps(nextProps, prevState) { // 在这里写你的逻辑,比如判断nextProps.user.isAuthenticated if (nextProps.user.isAuthenticated !== prevState.isAuthenticated) { return { isAuthenticated: nextProps.user.isAuthenticated }; } // 如果不需要更新state,返回null return null; } // ...其他代码 }
2. 确认Redux props是否真的发生了变化
虽然你说componentWillReceiveProps能正常触发,但还是要确认下:Redux store中user或global的更新是否生成了新的对象引用?
connect默认使用浅比较来判断props是否变化,如果你的reducer更新user时没有返回新对象(比如直接修改原对象的属性),connect会认为props没有变化,也就不会触发getDerivedStateFromProps(当然componentWillReceiveProps也不会触发,但你说它有效,所以这个可能不是你的问题)。
确保reducer里是不可变更新,比如:
// 错误:直接修改原对象 case 'LOGIN_SUCCESS': state.user.isAuthenticated = true; return state; // 正确:返回新对象 case 'LOGIN_SUCCESS': return { ...state, user: { ...state.user, isAuthenticated: true } };
3. 注意getDerivedStateFromProps的触发时机
和componentWillReceiveProps不同,getDerivedStateFromProps会在初始渲染和每次props/state更新时都触发,而componentWillReceiveProps只在props变化时触发(初始渲染不触发)。如果你的逻辑依赖初始渲染时的props,记得在getDerivedStateFromProps里处理这种情况。
内容的提问来源于stack exchange,提问作者Madeline Ries

