基于 Redux 状态更改的 React 事件侦听器

m00saca

下午好,

当我尝试根据状态更改重定向我的应用程序用户时,我在使用 React 和 Redux 时遇到了一些困难。

概括地说:当我user的状态对象填充了从 home//student/:username.

现在,我已经以一种古怪的方式实现了这一目标。

在我的Login组件中,componentDidUpdate当来自 3rd 方 API 的访问令牌从我的 Express 服务器传回客户端时,我使用生命周期挂钩来侦听和调度操作。

import React from "react";

import LoginForm from "../minor/LoginForm";

const Login = React.createClass({

  componentDidUpdate(){
    const {success, access_token} = this.props.loginStatus;

    if (success === true && access_token !== null){
      console.log("It worked getting your data now...");
      this.props.getUserData(access_token);
    } else if (success === false || access_token === null){
      console.log("Something went wrong...");
    } 

  }, 
render(){

    return(

        <div className="loginComponentWrapper">
          <h1>Slots</h1>
          <LoginForm loginSubmit={this.props.loginSubmit}
                     router={this.props.router}
                     user={this.props.user} />
          <a href="/register">New User?</a>
        </div>
      )
  }
});

请注意,我正在传递routeruser到我的LoginForm组件。我这样做是为了在另一个componentDidUpdate地方使用我使用该.push方法的地方,router如下所示:

import React from "react";

const LoginForm = React.createClass({


  componentDidUpdate(){
    const {router, user} = this.props;

    if (user.username !== null){
       router.push(`/student/${user.username}`);
    }
  },


  render(){

      return(
        <div className="loginWrapper">
          <div className="loginBox">
            <form className="loginForm" action="">
              <input ref={(input) => this.username_field = input} type="text" placeholder="username" defaultValue="[email protected]" />
              <input ref={(input) => this.password_field = input} type="text" placeholder="password" defaultValue="meowMeow3" />
              <button onClick={this.loginAttempt}>Login</button>
            </form>
          </div>
        </div>
        )
  }

});

当然它有效,但我确定这是一个过于复杂的解决方案,而不是被认为是最佳实践。我尝试在我的Login组件中添加一个自定义侦听器方法,但我从未成功触发过它,而是我的应用程序陷入了循环。

有没有办法使用 Redux 来做到这一点并保持我的组件更整洁,或者以componentDidUpdate更有效的方式利用?

与往常一样,我会感谢一些更有经验的人对我的问题的看法,并期待一些反馈!

谢谢

更新

App.js

import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import * as actionCreators from "../actions/userActions.js";

import StoreShell from "./StoreShell.js";

function mapStateToProps(state){
  return{
    loginStatus: state.loginStatus,
    user: state.user
  }
}

function mapDispatchToProps(dispatch){
  return bindActionCreators(actionCreators, dispatch)
}

const App = connect(mapStateToProps, mapDispatchToProps)(StoreShell);

export default App;

该组件“洒”我所有的终极版的东西和状态数据到我的容器组件命名StoreShell这反过来又通过了所有这些数据的道具组成像UI元素LoginLoginForm我会采取太多措施?

StoreShell.js

import React from "react";

const StoreShell = React.createClass({

    render(){

        return(

            <div className="theBigWrapper">
              {React.cloneElement(this.props.children, this.props)}
            </div>

          )

    }
})

export default StoreShell;
亚历克斯·杨

有几件事可以使登录流程更容易管理,并且可以稍微整理一下您的组件。先说几个一般点:

我不确定您为什么在两个组件之间划分登录逻辑?惯用的 React/Redux 方法是拥有一个处理逻辑的容器组件和一个处理表示的表示组件。目前这两个组件都做了一点点。

您不需要props.router上下传递组件。React 路由器提供了一个 HOC,该 HOC 将路由器作为道具提供,称为 withRouter(此处文档)。您只需在 withRouter 中包装一个组件,并且 props.router 可用 - 其他一切保持不变。

export default withRouter(LoginForm);

我个人的感觉是 URI 是应用程序状态的一部分,因此它应该在商店中维护并通过调度操作进行更新。有一个破解库可以做到这一点 - react-router-redux设置完成后,您可以将该push方法传递给您的组件(或其他地方...请参阅下一点)以进行导航:

import { push } from 'react-router-redux';
import { connect } from 'react-redux';

const NavigatingComponent = props => (
    <button onClick={() => props.push('/page')}>Navigate</button>
);

const mapStateToProps = null;
const mapDispatchToProps = {
    push
};

export default connect(mapStateToProps, mapDispatchToProps)(NavigatingComponent);

在我们的商店中使用 URI 的好处之一是我们不需要访问props.router来更改位置,这开辟了将登录逻辑移到我们组件之外的途径。有几种方法可以做到这一点,最简单的可能是redux-thunk,它允许我们的动作创建者返回函数而不是对象。然后我们可以编写我们的组件来简单地调用一个login输入用户名和密码函数,我们的 thunk 负责其余的工作:

import { push } from 'react-router-redux';

// action creators....
const loginStarted = () => ({
    type: 'LOGIN_STARTED'
)};

const loginFailed = (error) => ({
    type: 'LOGIN_FAILED',
    payload: {
       error
    }
};

const loginSucceeded = (user) => ({
    type: 'LOGIN_SUCCEEDED',
    payload: {
       user
    }
};

const getUserData = (access_token) => (dispatch) => {
    Api.getUserData(access_token) // however you get user data
    .then(response => {
        dispatch(loginSucceeded(response.user));
        dispatch(push(`/student/${response.user.username}`));
    });

export const login = (username, password) => (dispatch) => {
    dispatch(loginStarted());

    Api.login({ username, password }) // however you call your backend
    .then(response => {
        if (response.success && response.access_token) {
            getUserData(access_token)(dispatch);
        } else {
            dispatch(loginFailed(response.error));
        }
    });
}

您的组件唯一要做的就是调用初始登录功能,该功能可以实现如下:

容器:

import React from 'react';
import { connect } from 'react-redux';

import { login } from '../path/to/actionCreators';
import LoginForm from './LoginForm';

const LoginContainer = React.createClass({
    handleSubmit() {
        this.props.login(
           this.usernameInput.value,
           this.passwordInput.value
        );
    },

    setUsernameRef(input) {
        this.usernameInput = input;
    },

    setPasswordRef(input) {
        this.passwordInput = input;
    },

    render() {
        return (
           <LoginForm
              handleSubmit={this.handleSubmit.bind(this)}
              setUsernameRef={this.setUsernameRef.bind(this)}
              setPasswordRef={this.setPasswordRef.bind(this)}
           />
        );
    }
});

const mapStateToProps = null;
const mapDispatchToProps = {
    login
};

export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer);

成分:

import React from 'react';

export const LoginForm = ({ handleSubmit, setUsernameRef, setPasswordRef }) => (  
    <div className="loginWrapper">
        <div className="loginBox">
            <form className="loginForm" action="">
                <input ref={setUsernameRef} type="text" placeholder="username" defaultValue="[email protected]" />
                <input ref={setPasswordRef} type="text" placeholder="password" defaultValue="meowMeow3" />
                <button onClick={handleSubmit}>Login</button>
            </form>
        </div>
    </div>
);

这实现了逻辑/数据提供容器和无状态表示组件的分离。LoginForm 组件可以简单地写成上面的函数,因为它不负责处理逻辑。容器也是一个非常简单的组件——逻辑在我们的 action creator/thunk 中都被隔离了,并且更容易阅读和推理。

redux-thunk只是使用 redux 管理异步副作用的一种方法 - 还有许多其他方法具有不同的方法。我个人更喜欢redux-saga,这对你来说可能很有趣。然而,在我自己的 redux 之旅中,redux-thunk在发现它的局限性/缺点并继续前进之前,我肯定会从使用和理解中受益,并且会向其他人推荐这条路线。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

React:与事件侦听器相关的批处理状态更新

如何基于Redux状态更改使React组件setState()?

React.js状态更改的侦听器

基于先前状态更改 Redux 中的状态

如何将事件侦听器添加到React Native中的状态

为什么更新状态未反映在事件侦听器中:React Native,Hooks

如何使用react-select为搜索输入更改设置事件侦听器?

如何使用 React 将事件侦听器“更改时”添加到输入元素?

React / Redux - 基于状态变化创建 XHR 请求

无法基于“ wheel”事件侦听器增加值

套接字侦听器未从 React 状态获取更新

Firebase onDataChange - 值事件侦听器不侦听更改

如何获取我的Firebase侦听器以在React Native应用程序中将数据加载到Redux状态,以便可以在ComponentDidMount函数中读取数据?

更改状态 onClick React+Redux

React redux - 更改单个状态项的属性

如何基于电子菜单单击更改Redux状态?

反应导航焦点事件侦听器返回旧状态

状态未按预期在事件侦听器之间更新

canvas事件侦听器切换参数状态

网络的 Lottie 事件侦听器和状态 - javascript

为什么反应事件侦听器正在保存状态?

如何向 React 组件添加事件侦听器?

react组件中的onDeviceReady事件侦听器

React keydown 事件侦听器被多次调用?

对 React 事件侦听器内存泄漏的担忧

期望onClick侦听器是一个函数,而不是类型对象-react redux

文本更改事件未进入侦听器

URL参数更改时的侦听器事件

Symfony2:将事件更改为侦听器