反应传奇生命周期

时间:2016-12-31 17:24:13

标签: reactjs redux redux-saga

以下是我的登录传奇的片段:

Note: The Breaker block may not be the appropriate switching device to
use for DC circuits. For such applications, it is recommended that you
use the Ideal Switch block as a switching device.

这个传奇在我的LoginContainer中。现在,每当我进入登录屏幕并加载登录容器时,就会产生一个新的传奇“进程”,所以每当我重新访问登录界面时,当我点击“登录”时,我的登录API的请求越来越多按钮。

我可以以某种方式破坏组件破坏时的传奇吗?

编辑:这是尝试取消传奇:

export function* loginFlow() {
  while (true) {
    const request = yield take(LOGIN_REQUEST);
    const { username, password } = request.data;

    const authResp = yield call(authorize, { username, password });
    if (authResp) {
      yield put({ type: SET_AUTH, newAuthState: true }); // User is logged in (authorized)
      yield put({ type: CHANGE_FORM, newFormState: { username: '', password: '' } }); // Clear form
      forwardTo('/home'); // Go to dashboard page
    }
  }
}

我必须在初始加载时单击登录按钮两次,以便完全发出API请求,然后我遇到与以前相同的行为 - saga不会被取消并且请求不断加起来

这是我的组件:

export function* loginFlow() {
  const request = yield take(LOGIN_REQUEST);
  const { username, password } = request.data;

  const authResp = yield call(authorize, { username, password });
  if (authResp) {
    yield put({ type: SET_AUTH, newAuthState: true }); // User is logged in (authorized)
    yield put({ type: CHANGE_FORM, newFormState: { username: '', password: '' } }); // Clear form
    forwardTo('/home'); // Go to dashboard page
  }
}

export function* watchLogin() {
  // or takeEvery (according to your business logic)
  yield* takeEvery(LOGIN_REQUEST, loginFlow);
}

export function* root() {
  const watchers = [
    yield fork(watchLogin),
  ];

  // Cancel all watchers on location change
  yield take(LOCATION_CHANGE);

  watchers.forEach(function(watcher) {
    console.log("cancelling watcher")
    cancel(watcher)
  });
}

// All sagas to be loaded
export default [
  root,
];

这是我如何加载我的传奇(routes.js):

export class Login extends React.Component {
  constructor(props) {
    super(props);
    this.login = this.login.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  onChange(newFormState) {
    this.props.dispatch(changeForm(newFormState));
  }

  login(username, password) {
    console.log("dispatching login request")
    this.props.dispatch(loginRequest({ username, password }));
  }

  render() {
    const { formState, currentlySending, error } = this.props;

    return (
      <Wrapper>
        <LoginForm onChange={this.onChange} data={formState} error={error} currentlySending={currentlySending} btnText={messages.btnText} usernameText={messages.usernameText} passwordText={messages.passwordText} onSubmit={this.login} />
      </Wrapper>
    );
  }
}

这是我认为导致问题的forwardTo函数:

export default function createRoutes(store) {
  // create reusable async injectors using getAsyncInjectors factory
  const { injectReducer, injectSagas } = getAsyncInjectors(store);

  return [
    {
      path: '/login',
      name: 'login',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          System.import('containers/Login/reducer'),
          System.import('containers/Login/sagas'),
          System.import('containers/Login'),
        ]);

        const renderRoute = loadModule(cb);

        importModules.then(([reducer, sagas, component]) => {
          injectReducer('login', reducer.default);
          injectSagas(sagas.default);
          renderRoute(component);
        });

    importModules.catch(errorLoading);
  },
...

如果我在saga的while循环中调用此函数之前中断,则saga会自动销毁并且所有工作都按预期工作。

1 个答案:

答案 0 :(得分:0)

嗯,是的,你可以通过组件破坏摧毁你的传奇观察者,这可能是通过两种方法:

  1. 添加到组件装载和卸载的操作,然后在您的React组件的方法componentWillMount中,调度装载操作,并在componentWillUnmount发送卸载操作并相应地处理您的传单。 / p>

  2. 你会在页面/容器上破坏你的传奇观察者而不是组件破坏,你只需听LOCATION_CHANGE行动(如果你是react-router-redux使用它而不是COMPONENT_UNMOUNT动作(,如上面第一种方法中提到的

  3. 您可以在此处获取在您的传奇中应用第二种方法的示例,以及对loginFlow saga生成器的一些修改:

    import {call, cancel, fork, put, take} from 'redux-saga/effects';
    import {takeEvery, takeLatest} from 'redux-saga';
    import {LOCATION_CHANGE} from 'react-router-redux';
    import {
      LOGIN_REQUEST,
      SET_AUTH,
      CHANGE_FORM,
    } from './constants';
    
    export function* loginFlow() {
      const request = yield take(LOGIN_REQUEST);
      const { username, password } = request.data;
    
      const authResp = yield call(authorize, { username, password });
      if (authResp) {
    
        // User is logged in (authorized)
        yield put({ type: SET_AUTH, newAuthState: true });
    
        // Clear form
        yield put({ type: CHANGE_FORM, newFormState: {
          username: '',
          password: ''
        } });
    
        forwardTo('/home'); // Go to dashboard page
      }
    }
    
    export function* watchLogin() {
      // or takeEvery (according to your business logic)
      yield* takeLatest(LOGIN_REQUEST, loginFlow);
    }
    
    export function* root() {
      const watchers = [
        yield fork(watchLogin),
      ];
    
      // Cancel all watchers on location change
      yield take(LOCATION_CHANGE);
      watchers.forEach(cancel);
    }
    
    // All sagas to be loaded
    export default [
      root,
    ];
    

    现在如上所示,我们使用了一些redux-saga/effects fork saga观察者关于组件/容器的使用情况,然后使用取消来销毁{}上的观察者{1}}。

    此外,您需要在LoginComponent中的buttonClick上发送LOCATION_CHANGE动作。

    如果不清楚,请询问澄清。

    LOGIN_REQUEST文档here了解有关任务取消的详情。