在使用react / redux进行组件渲染之前从特定状态获取值?

时间:2017-06-30 16:11:50

标签: reactjs redux react-redux

我正在使用react / redux和nodejs(express)/ mongodb后端的帮助。

我想在这里发生的是,如果用户试图编辑不属于他们的帖子,我希望他们立即重新路由并且永远不会看到该页面。

例如。用户" A"转到路由localhost:8080/posts/post_id/edit,但该帖子属于用户" B"。我希望用户A立即重新路由回该帖子或localhost:8080/posts/post_id

在我的代码中,我可以让用户通过一个名为getUser()的操作,该操作向后端发送axios.get请求以获取当前登录的用户。我正在使用JWT令牌。不确定这是否是需要的信息。

这是代码,向您展示我想要做的事情。

import React , { Component } from 'react';
import { bindActionCreators } from 'redux';
import * as actions from '../../actions/posts_actions';
import * as actionsIndex from '../../actions/index';
import { reduxForm, Field } from 'redux-form';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom';

class EditPost extends Component {
  componentWillMount() {
    if(this.props.auth) {
      console.log(this.props.auth); // -> returns true
      this.props.getUser(); // -> this fires off
    }
  }

  componentDidMount() {
    const {id} = this.props.match.params;
    this.props.getOnePost(id);
    if(this.props.auth){
      if(this.props.user._id !== this.props.post.author.id){
        this.props.history.push(`/posts/${id}`);
      }
    }
  }

  renderField(field) {
    const { meta: {touched, error} } = field;
    const className = `form-group ${touched && error ? 'has-danger' : ''}`;

    return (
      <div className={className}>
        <label><strong>{field.label}:</strong></label>
        <input
          className="form-control"
          type={field.type}
          {...field.input}
        />
        <div className="text-help">
          { touched ? error : ''}
        </div>
      </div>
    )
  }

  onSubmit(values) {
    const {id} = this.props.match.params;

    this.props.updatePost(values, id, () => {
      this.props.history.push(`/posts/${id}`);
    });
  }

  render() {
    const {handleSubmit} = this.props;

    const {id} = this.props.match.params;
    console.log(this.props.user); // -> shows me the user after three nulls
    return (
      <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
        <Field
          label="Title"
          name="title"
          type="text"
          component={this.renderField}
        />
        <Field
          label="Content"
          name="content"
          type="text"
          component={this.renderField}
        />
        <button type="submit" className="btn btn-success">Submit</button>
        <Link to={`/posts/${id}`} className="btn btn-danger">Cancel</Link>
      </form>
    );
  }
}

function validate(values) {
  const errors = {};

  if(!values.title) {
    errors.title = "Enter a title!";
  }
  if(!values.content) {
    errors.content = "Enter some content please!";
  }

  return errors;
}

function mapStateToProps({ posts, auth, user }, ownProps) {
  return {
    initialValues: posts[ownProps.match.params.id],
    post: posts[ownProps.match.params.id],
    auth: auth.authenticated,
    user: user
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({...actions, ...actionsIndex}, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(reduxForm({
  validate,
  form: 'editform'
})(EditPost));

以下是console.log语句:

enter image description here

这是index.js页面的编辑,有什么办法可以在这里更新用户状态吗?:

"use strict"
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import { applyMiddleware, createStore } from 'redux';
import reduxThunk from 'redux-thunk';
import reducers from './reducers/index';
import App from './components/app';
import '../style/style.css';

import Home from './components/pages/home';
import Header from './components/header';
import Footer from './components/footer';
import RequireAuth from './components/auth/require_auth';
import RequireUnAuth from './components/auth/require_unauth';

import Signin from './components/auth/signin';
import Signup from './components/auth/signup';
import Signout from './components/auth/signout';

import Posts from './components/pages/posts';

import {AUTH_USER} from './actions/types';

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);

const token = localStorage.getItem('token');

if(token) {
  store.dispatch({ type: AUTH_USER });
}

const Routes = (
  <Provider store={store}>
    <BrowserRouter>
    <App />
    </BrowserRouter>
  </Provider>
)

ReactDOM.render(Routes, document.querySelector('.container'));

2 个答案:

答案 0 :(得分:0)

如果this.props.getUser()是异步(thunk-ed)动作创建者,则当您到达componentDidMount

时,您无法保证其结果可用

在尝试访问其中的字段之前,在this.props.user中为componentDidMount添加空检查。

你能做的就是搬家

if(this.props.user._id !== this.props.post.author.id){
  this.props.history.push(`/posts/${id}`);
}

进入componentWillReceiveProps

componentWillReceiveProps ({ user: nextUser }) {
    const { history, match, user: currentUser, post } = this.props
    const { id } = match.params

    /* if you didn't previously have currentUser (i.e. after first load) - !currentUser
     * or the user has changed - nextUser !== currentUser*/
    if (!currentUser || nextUser !== currentUser) { // probably shouldn't use === here
      /* the component might update before `this.props.getUser()` "returns", so make sure this is the
       * update we are looking for by ensuring that we have nextUser -  nextUser &&
       * then get the id (nextUser._id), and run the check (!== post.author.id)*/
      if (nextUser && (nextUser._id !== post.author.id)) {
        history.push(`/posts/${id}`)
      }
    }
  }
componentWillReceiveProps上的{p> Here's a little light Friday reading - 可能会清除一些内容。

有关编辑的一些事项:

  1. 如果你有很多依赖user
  2. 的组件,HoC可能是一个好主意。

    AuthComponent HoC概念

    class AuthComponent extends React.Component {
      componentDidMount() {
        if (!this.props.user) {
          this.props.getUser()
        }
      }
    
      render() {
        // you could inject `user` into children here, but I would suggest that you 
        // instead store the result of `getUser` into a store like `redux` or `flux` and fetch from that in child components
        return this.props.children
      }
    }
    

    显然,你需要使用connect并从状态中抓取user来获取此组件。你会像

    一样使用它
    class SomeComponent extends React.Component {
      render () {
        return (
          <AuthComponent>
            <WrappedComponent/> // <- this is what's rendered
          </AuthComponent>
        )
      }
    } 
    

    您正在使用react-router,因此更好的解决方案是将其纳入您的路由

    <Route path="" component={AuthComponent}>
      <Route path="some-path" component={WrappedComponent}/>
    </Route> 
    
    1. 就像我在评论中说的那样,缓存并从您的商店返回user ...虽然看起来您已经这样做了
    2. 请勿假设您始终可以访问user - 请确保您无效检查

答案 1 :(得分:0)

您在componentWillMount中使用的代码不属于此处。

this.props.getUser();

您最好创建一个动作redux-thunk创建者,它处理promise +异步操作,然后通过状态/调度机制返回结果,以便稍后在componentDidMount生命周期钩子中使用。

要调用API的Redux thunk示例,请查看redux-thunk docs:

const store = createStore(
  reducer,
  applyMiddleware(thunk.withExtraArgument(api))
)

// later
function fetchUser(id) {
  return (dispatch, getState, api) => {
    // you can use api here
  }
}
To pass multiple things, just wrap them in a single object and use destructuring:

const store = createStore(
  reducer,
  applyMiddleware(thunk.withExtraArgument({ api, whatever }))
)

// later
function fetchUser(id) {
  return (dispatch, getState, { api, whatever }) => {
    // you can use api and something else here here
  }
}