javascript 构造函数被调用两次React组件

ijxebb2r  于 2023-01-24  发布在  Java
关注(0)|答案(7)|浏览(141)

我的react组件的构造函数被调用了两次,但我不知道为什么。我正在使用react-redux来存储我的应用程序的语言。我有一个函数可以根据浏览器的语言设置默认语言。LoginPage是第一个被渲染的组件,所以我在它的构造函数中调用了我的函数。基本上,它所做的是比较和分派一个操作。当我用redux开发工具检查我的状态时,我发现它被调度了两次,我在构造函数中打印了伪数据,它也被打印了两次。
LoginPage.js

import React from 'react';
import {connect} from 'react-redux';
import {startLogin} from '../actions/auth';
import {setLanguage} from '../actions/lang';

export class LoginPage extends React.Component{

  constructor(props){
    super(props);
    this.setDefaultLanguage();
    console.log('i am constructor');
  }

  changeLanguage = (e) => {
    const lan = e.target.value;
    this.props.setLanguage(lan);
  };

  setDefaultLanguage = () => {
    const defaultLanguage = navigator.language || navigator.userLanguage || 'en-US';

    if(defaultLanguage == 'es'){
      this.props.setLanguage(defaultLanguage);
    }else{
      this.props.setLanguage('en');
    }
  }

  render(){
    return(
      <div className="box-layout">
        <div className="box-layout__box">
          <h1 className="box-layout__title">Expensify</h1>
          <p>It\'s time to get your expenses under control.</p>
          <button className="button" onClick={this.props.startLogin}>Log in with google</button>
          <select className="select" onChange={this.changeLanguage}>
            <option value="en">English</option>
            <option value="es">Español</option>
          </select>
        </div>
      </div>
    )
  };
}

const mapDispatchToProps = (dispatch) => ({
  startLogin: () => dispatch(startLogin()),
  setLanguage: (language) => dispatch(setLanguage(language))
});

export default connect(undefined, mapDispatchToProps)( LoginPage);

App.js

import React from 'react';
import ReactDom from 'react-dom';
import {Router, Route, Switch} from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import ExpenseDashBoardPage from '../components/ExpenseDashBoardPage';
import AddExpensePage from '../components/AddExpensePage';
import EditExpensePage from '../components/EditExpensePage';
import NotFoundPage from '../components/NotFoundPage';
import LoginPage from '../components/LoginPage';
import PrivateRoute from './PrivateRoute';
import PublicRoute from './PublicRoute';

export const history = createHistory();

const AppRouter = () => (
  <Router history={history}>
    <div>
      <Switch>
        <PublicRoute path="/" component={LoginPage} exact={true} />
        <PrivateRoute path="/dashboard" component={ExpenseDashBoardPage} />
        <PrivateRoute path="/create" component={AddExpensePage} />
        <PrivateRoute path="/edit/:id" component={EditExpensePage} />
        <Route component={NotFoundPage} />
      </Switch>
    </div>

  </Router>
)

export default AppRouter;
koaltpgm

koaltpgm1#

首先,你不应该在构造函数中调用Redux操作或者任何类型的 AJAX ,这些事情应该在componentDidMount()中完成。
其次,我会从商店请求语言作为 prop 的一部分。如果没有定义,那么在componentDidMount()中调用您的setDefaultLanguage()
我至少会做到以下几点:

export class LoginPage extends React.Component {
  componentDidMount() {
    if (!this.props.lang) {
        this.setDefaultLanguage();
    }
  }

  changeLanguage = (e) => {
    const lan = e.target.value;
    this.props.setLanguage(lan);
  };

  setDefaultLanguage = () => {
    const defaultLanguage = navigator.language || navigator.userLanguage || 'en-US';

    if(defaultLanguage == 'es'){
      this.props.setLanguage(defaultLanguage);
    }else{
      this.props.setLanguage('en');
    }
  }

  render() {
    return(
      <div className="box-layout">
        <div className="box-layout__box">
          <h1 className="box-layout__title">Expensify</h1>
          <p>It\'s time to get your expenses under control.</p>
          <button className="button" onClick={this.props.startLogin}>Log in with google</button>
          <select className="select" onChange={this.changeLanguage}>
            <option value="en">English</option>
            <option value="es">Español</option>
          </select>
        </div>
      </div>
    )
  };
}

const mapStateToProps = state => ({
    // Assuming `steate.lang` is where you would set the language.
    lang: state.lang
});

const mapDispatchToProps = (dispatch) => ({
  startLogin: () => dispatch(startLogin()),
  setLanguage: (language) => dispatch(setLanguage(language))
});

const mergeProps = (stateProps, dispatchProps) => ({ ...stateProps, ...dispatchProps });

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(LoginPage);
fjnneemd

fjnneemd2#

我遇到了同样的问题,因为我在我的公共路由中重定向用户。所以它呈现了组件两次。如果您使用

history.push('/');

这将呈现组件两次。

9lowa7mx

9lowa7mx3#

这两次调用一些生命周期方法,仅适用于开发模式。

“在生产模式下不会双重调用生命周期。"

iqih9akk

iqih9akk4#

是的。这是有意的,并在这里记录。它只发生在开发模式。
https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects

ma8fv8wu

ma8fv8wu5#

如果你检查React Dev Tools中正在渲染的内容,你会看到类似connect(App)的内容以及App本身,所以你的console.log会被调用两次,这是因为connect是一个更高阶的组件。
如果您将this.setDefaultLanguage()(以及您的console.log,这样您就可以看到它的运行)移出构造函数并放入componentDidMount生命周期钩子,它应该可以修复您的问题。

3htmauhk

3htmauhk6#

    • 溶液:将索引. js中的"React. StrictMode"替换为"〈〉"**
    • 原因:**状态和生命周期方法不包含副作用非常重要。忽略此规则可能会导致各种问题,包括内存泄漏和无效的应用程序状态。遗憾的是,由于这些问题通常具有不确定性,因此很难检测到。
    • 严格模式不能自动检测副作用,但它可以通过使副作用更具确定性来帮助您发现副作用。这可以通过有意地双重调用以下函数来实现:**

1.构造器
1.渲染
1.应该组件更新
1.从属性获取派生状态
1.功能组件主体
1.状态更新器函数(setState的第一个参数)
1.传递给useState、useMemo或useReducer的函数

    • 这仅适用于开发模式。在生产模式下不会双重调用生命周期。**
yftpprvb

yftpprvb7#

可以使用index.js中的以下代码禁用开发模式

//  <React.StrictMode>
    <Application />
//  </React.StrictMode>

相关问题