Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何订阅React组件中的Redux操作_Javascript_Reactjs_Redux_Redux Saga_React Boilerplate - Fatal编程技术网

Javascript 如何订阅React组件中的Redux操作

Javascript 如何订阅React组件中的Redux操作,javascript,reactjs,redux,redux-saga,react-boilerplate,Javascript,Reactjs,Redux,Redux Saga,React Boilerplate,我试图弄清楚如何在React组件中订阅Redux操作。 我在谷歌上找不到任何东西,所以我在这里打开一个问题,看看是否有人能帮我 当用户尝试登录时,我会发送一个loginRequestation(),然后使用redux saga(查看下面我的saga.js文件)进行处理,最后,如果一切正常,我会发送LOGIN\u REQUEST\u SUCCESS操作 我想在这里做的是找到一种在我的React组件中订阅LOGIN\u REQUEST\u SUCCESS操作的方法,这样一旦收到操作,我就可以更新我的

我试图弄清楚如何在React组件中订阅Redux操作。 我在谷歌上找不到任何东西,所以我在这里打开一个问题,看看是否有人能帮我

当用户尝试登录时,我会发送一个
loginRequestation()
,然后使用
redux saga
(查看下面我的
saga.js
文件)进行处理,最后,如果一切正常,我会发送
LOGIN\u REQUEST\u SUCCESS
操作

我想在这里做的是找到一种在我的React组件中订阅
LOGIN\u REQUEST\u SUCCESS
操作的方法,这样一旦收到操作,我就可以更新我的React组件本地状态,并使用
history.push()
将用户重定向到仪表板页面

这是我的组件代码:

/**
 *
 * LoginPage
 *
 */

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';
import { Container, Row, Col, Button, Alert } from 'reactstrap';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';
import { ReactstrapInput } from 'reactstrap-formik';
import reducer from './reducer';
import saga from './saga';
import { loginRequestAction } from './actions';
import { makeSelectLoginPage } from './selectors';
import { makeSelectIsLogged } from '../Auth/selectors';

const LoginSchema = Yup.object().shape({
  userIdentifier: Yup.string().required('Required'),
  password: Yup.string().required('Required'),
});

/* eslint-disable react/prefer-stateless-function */
export class LoginPage extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      formMsg: {
        color: '',
        text: '',
      },
    };
  }

  componentDidMount() {
    const { history, isLogged } = this.props;

    if (isLogged) history.push('/dashboard/index');
  }

  render() {
    const { formMsg } = this.state;
    const { onLoginFormSubmit } = this.props;

    return (
      <div>
        <Helmet>
          <title>Sign in</title>
          <meta name="description" content="Description of LoginPage" />
        </Helmet>
        <Container className="auth-container">
          <div className="form-page">
            <Row>
              <Col className="text-center">
                <img
                  className="mb-4"
                  src="https://getbootstrap.com/docs/4.1/assets/brand/bootstrap-solid.svg"
                  alt=""
                  width="72"
                  height="72"
                />
              </Col>
            </Row>
            <Row>
              <Col className="text-center">
                {' '}
                <h1 className="h3 mb-3 font-weight-normal">Authentication</h1>
                <Alert
                  color={formMsg.color}
                  role="alert"
                  className={formMsg.text ? '' : 'd-none'}
                >
                  <strong>{formMsg.text}</strong>
                </Alert>
              </Col>
            </Row>

            <Formik
              initialValues={{
                userIdentifier: '',
                password: '',
              }}
              validationSchema={LoginSchema}
              onSubmit={onLoginFormSubmit}
            >
              {({ isSubmitting }) => (
                <Form>
                  <Field
                    component={ReactstrapInput}
                    name="userIdentifier"
                    type="userIdentifier"
                    placeholder="john@acme.com"
                    label="E-mail address"
                  />
                  <Field
                    component={ReactstrapInput}
                    name="password"
                    type="password"
                    placeholder="Password"
                    label="Password"
                  />
                  <div>
                    <Button
                      type="submit"
                      block
                      size="lg"
                      color="primary"
                      disabled={isSubmitting}
                    >
                      <FontAwesomeIcon
                        pulse
                        icon={faSpinner}
                        className={isSubmitting ? 'mr-2' : 'd-none'}
                      />
                      Log in to access
                    </Button>
                  </div>
                </Form>
              )}
            </Formik>

            <Link to="/auth/reset">
              <Button size="sm" color="secondary" block className="mt-2">
                Forgot password?
              </Button>
            </Link>
            <p className="mt-5 mb-3 text-center">
              <Link to="/auth/register">
                Don&#39;t have an account? Sign up
              </Link>
            </p>
          </div>
        </Container>
      </div>
    );
  }
}

LoginPage.propTypes = {
  isLogged: PropTypes.bool,
  history: PropTypes.object,
  onLoginFormSubmit: PropTypes.func,
};

const mapStateToProps = createStructuredSelector({
  loginpage: makeSelectLoginPage(),
  isLogged: makeSelectIsLogged(),
});

function mapDispatchToProps(dispatch) {
  return {
    onLoginFormSubmit: values => dispatch(loginRequestAction(values)),
  };
}

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);

const withReducer = injectReducer({ key: 'loginPage', reducer });
const withSaga = injectSaga({ key: 'loginPage', saga });

export default compose(
  withReducer,
  withSaga,
  withConnect,
)(LoginPage);
另外,我来自GitHub问题:(请看一看,因为有一个可能的解决方案,但我认为这不是正确的方法)。

通常,您从不“订阅”组件中的Redux操作,因为它破坏了React的一些声明性好处。大多数情况下,您只需通过道具
connect()
到Redux状态,然后根据这些道具进行渲染。订阅操作,然后在响应中调用路由函数是命令式编程,而不是声明式编程,因此您需要在组件中避免这种情况

因此,在处理sagas时,对于这种场景,您有两种选择。您不必从您的传奇中发出
LOGIN\u REQUEST\u SUCCESS
,只需从传奇本身内部推送一条新路线即可:

yield call(push, '/foo')

或者在Redux状态下维护
authenticated:boolean
属性,在用户登录时将其翻转到saga中的
true
,然后使用它在组件中有条件地呈现react路由器
(或者有条件地呈现应用程序的整个经过身份验证的树,由您决定).

老实说,我认为github中的答案是有道理的。您可以使用reducer在redux中订阅分派操作。以及负责设置redux状态并使用connect函数将其返回到组件的reducer


在我看来,添加一个名为“LoginSucess”的flag属性或其他任何内容并传递给您的组件不会导致性能问题,因为这是redux与react的工作方式

如果有人来自谷歌,试图解决类似问题并阅读了本文,我所做的就是遵循Jed Richards的建议。此外,我还做了更多的事情:当一个组件从DOM中删除时,我
dispatch
a
reset
中的操作
component将卸载
以清除Redux状态,因此它释放的状态不会在应用程序的其他部分中使用,并且是无用的。这是错误的。它不会破坏React的声明性好处。在组件中执行提取是订阅大小为1的流。当该流发出时,执行
setState
更新组件。使用connect是订阅无限大的状态流,而
connect
本身调用
setState
来更新组件。类似地,你可以订阅redux的动作流并做一些副作用,而这丝毫不会破坏react的任何好处。仅仅因为
react-redux
没有提供API不会出错。我从来没有说过在react组件中订阅任何东西都是错误的——我说订阅操作是错误的。从redux action创建者或thunk处返回获取承诺,并在组件中使用该承诺,而不是通过商店进行适当的往返,这是一个常见的初学者错误,因此我想让OP远离这个术语。显然,一般订阅内容并在组件中产生副作用是可以的——我的答案与redux+saga模式密切相关。这就是我所指的。从组件内部订阅redux的操作完全可以。我谈到了其他副作用和其他可订阅通道,因为它们与订阅操作没有任何区别。任何人如果不这样说,都必须提出一个非常好的论点和支持该论点的证据。
yield call(push, '/foo')