【问题标题】:one of my controllers is not rendering when I update the store当我更新商店时,我的一个控制器没有呈现
【发布时间】:2017-12-05 17:23:50
【问题描述】:

我试图学习反应,但是当我设置经过身份验证的道具时,我一直坚持让标头组件重新呈现。我读了很多关于它的文章,但是有这么多不同的编码风格,我似乎无法有效地实现它们中的任何一种。当 this.props.authenticated 更改时,我试图让它重新渲染。这是我的最新尝试,我无法让它在代码的较小部分上工作,所以我想我会做整个块。

import React, { Component, PropTypes } from 'react';
import logo from '../logo.svg';
import { Link } from 'react-router-dom';
import {connect} from 'react-redux';
import * as Actions from '../actions/auth';

class Header extends Component {

constructor() {
    super();
    this.state = { authenticated: false };
  }

    handleSignout() {
    this.props.signOutUser();
    }   

    logOut(event) {
    event.preventDefault();
    this.props.actions.logOutUser();
  }

  render() {
        if (this.props.authenticated){
            return (
                <div>
                    <div className="App">
                        <div className="App-header">
                        <img src={logo} className="App-logo" alt="logo" />
                        <h2>Student Assist App</h2>
                        </div>
                    </div>
                    <div className="navMenu">
                        <ul>
                            <li><Link to="/">Home</Link></li>
                            <li><Link to="/PhoneNumbers">PhoneNumbers</Link></li>
                            <li><Link to="/Addresses" > Addresses</Link></li>
                            <li><Link to="/Credits" > Credits</Link></li>

                        </ul>
                    </div>
                    <div className="authMenu">
                        <ul className="list-inline">
                            {/*<li><img src={profile.picture} height="40px" /></li>
                            <li><span>Welcome, {profile.nickname}</span></li>*/}
                            <Link to="/Home" > logout</Link>
                        </ul>

                    </div>
                </div>
            );
    }else{
            return (
                <div>
                    <div className="App">
                        <div className="App-header">
                        <img src={logo} className="App-logo" alt="logo" />
                        <h2>Student Assist App</h2>
                        </div>
                    </div>
                    <div className="navMenu">
                        <ul>
                            <li><Link to="/">Home</Link></li>
                            <li><Link to="/PhoneNumbers">PhoneNumbers</Link></li>
                            <li><Link to="/Addresses" > Addresses</Link></li>
                            <li><Link to="/Credits" > Credits</Link></li>

                        </ul>
                    </div>
                    <div className="authMenu">
                        <ul className="list-inline">
                            <li><Link to="/SignUp" > Sign Up</Link></li>
                            <li><Link to="/Login" > Login</Link></li>
                        </ul>
                    </div>
                </div>
            );
    }

  }
}

Header.propTypes = {  
  actions: PropTypes.object.isRequired
}

function mapStateToProps(state, ownProps) {  
  return {
    authenticated: state.authenticated
    }
}

export default connect(mapStateToProps, Actions)(Header);

标头位于应用容器中。

import React, { Component, PropTypes } from 'react';
import { ConnectedRouter } from 'react-router-redux';
import { connect } from 'react-redux'
import { history } from '../store/configureStore';
import { Route, Redirect } from 'react-router-dom';

import Header from '../components/header'
import Home from '../components/home'
import Addresses from '../containers/addresses'
import PhoneNumbers from '../containers/phoneNumbers'
import NotAuthroised from '../components/notAuthorised'
import Credits from '../components/credits'
import LogInPage from '../components/logInPage'
import LogIn from '../components/logInPage'
import SignUp from '../containers/signup'

import '../css/App.css';

const PrivateRoute = ({component: Component, authenticated, ...props}) => {
    return (
        <Route
            {...props}
            render={(props) => authenticated === true
                ? <Component {...props} />
                : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
        />
    );
};

class App extends Component {
  constructor(props) {
    super(props)
    this.handleLoginClick = this.handleLoginClick.bind(this)
    this.handleLogoutClick = this.handleLogoutClick.bind(this)
  }

  handleLoginClick() {
    this.props.login()
  }

  handleLogoutClick() {
    this.props.logout()
  }

  render() {
    const { authenticated, profile } = this.props
    return (
      <ConnectedRouter history={history}>
        <div>
          <Header 
            authenticated={authenticated}
            profile={profile}
            onLoginClick={this.handleLoginClick}
            onLogoutClick={this.handleLogoutClick}
          />

          <Route exact={true} path="/" component={Home}/>
          <Route path="/Home" component={Home}/>
          <Route path="/PhoneNumbers" component={PhoneNumbers}/>
          <PrivateRoute authenticated={this.props.authenticated } path="/Addresses" component={Addresses}/>
          <Route path="/NotAuthroised" component={NotAuthroised}/>
          <Route path="/Credits" component={Credits}/>
          <Route path="/Login" component={LogIn}/>
          <Route path="/SignUp" component={SignUp}/>


        </div>
      </ConnectedRouter>
    );
  }
}

const mapStateToProps = (state) => {
    return { authenticated: state.auth.authenticated };
};

export default connect(mapStateToProps)(App);

在 index.js 中调用 app 容器

import './index.css';

import { Provider } from 'react-redux';
import { configureStore } from './store/configureStore'
import App from './containers/App';
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';

const store = configureStore()
//store.dispatch(loadAddresses());


ReactDOM.render(<Provider store={store}> 
                    <App />
                </Provider>, 
                document.getElementById('root'));
registerServiceWorker();

改变authenticated值的登录组件是

import React, {PropTypes} from 'react';  
import TextInput from './common/textInput';  
import {bindActionCreators} from 'redux';  
import {connect} from 'react-redux';  
import * as sessionActions from '../actions/auth';

class LogInPage extends React.Component {  
  constructor(props) {
    super(props);
    this.state = {credentials: {email: '', password: ''}}
    this.onChange = this.onChange.bind(this);
    this.onSave = this.onSave.bind(this);
  }

  onChange(event) {
    const field = event.target.name;
    const credentials = this.state.credentials;
    credentials[field] = event.target.value;
    return this.setState({credentials: credentials});
  }

  onSave(event) {
    event.preventDefault();
    this.props.actions.signInUser(this.state.credentials);
  }

  render() {
    return (
      < div>
        < form>
          < TextInput
            name="username"
            label="Username"
            value={this.state.credentials.username}
            onChange={this.onChange}/>

          < TextInput
            name="password"
            label="password"
            type="password"
            value={this.state.credentials.password}
            onChange={this.onChange}/>

          < input
            type="submit"
            className="btn btn-primary"
            onClick={this.onSave}/>
        </form>
      </div>

  );
  }
}

function mapDispatchToProps(dispatch) {  
  return {
    actions: bindActionCreators(sessionActions, dispatch)
  };
}
export default connect(null, mapDispatchToProps)(LogInPage);

signInUser 方法在 actions/auth.js 中

import * as types from './actionTypes';  
import decode from 'jwt-decode';
import sessionApi from '../api/authApi';

const ID_TOKEN_KEY = 'jwt'

export function signOutUser() {
    sessionStorage.removeItem(ID_TOKEN_KEY);
    return {
        type: types.SIGN_OUT_USER
    }
}

export function signInUser(credentials) {
    console.log('singing user is with credentials ' +  credentials);
    return function(dispatch) {
      return sessionApi.login(credentials).then(response => {
        sessionStorage.setItem(ID_TOKEN_KEY, response.access_token);
        dispatch(authUser());
      }).catch(error => {
        console.log('we caught an error ' + error)
        dispatch(authError(error));
      });
    };
}

export function isLoggedIn() {
    return function(dispatch) {
        const idToken = getIdToken()
        if (!!idToken && !isTokenExpired(idToken)){
            dispatch(authUser());
        }else{
            console.log('is logged in issue ')
            dispatch(authError('Not logged in'));
        }
    }
}

export function getIdToken() {
  console.log('the token is now ' + sessionStorage.getItem(ID_TOKEN_KEY));
  return sessionStorage.getItem(ID_TOKEN_KEY);
}

function getTokenExpirationDate(encodedToken) {
  console.log('in get Exp date with encoded token ' + encodedToken);
  const token = decode(encodedToken);
  if (!token.exp) { return null; }

  const date = new Date(0);
  date.setUTCSeconds(token.exp);

  return date;
}

function isTokenExpired(token) {
  console.log('were in isTokenExpired');
  const expirationDate = getTokenExpirationDate(token);
  return expirationDate < new Date();
}

export function authUser() {
    return {
        type: types.AUTH_USER
    }
}

export function authError(error) {
    return {
        type: types.AUTH_ERROR,
        payload: error
    }
}

认证reducer是

import * as types from '../actions/actionTypes';  
import initialState from './initialState';  
//import history from '../history'

export default function auth(state = initialState, action) {
  switch (action.type) {
    case types.AUTH_USER:
      console.log('we have an auth user request')
      return {
        authenticated: true,
        error : null
      };
    case types.SIGN_OUT_USER:
    console.log('we have an sign out request')
      return {
        authenticated: false,
        error : null
      };
    case types.AUTH_ERROR:
    console.log('we have an auth error request')
      return {
        error: action.payload.message
      };
    default:
      return state;
  }
}

组合的reducer是rootReducer

import * as ActionTypes from '../actions/auth'
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer } from 'redux-form';
import phoneNumbers from './phoneNumbers';
import addresses from './addresses';
import auth from './auth';

const rootReducer = combineReducers({
    auth,
    addresses,
    phoneNumbers,
    routerReducer,
    reducer
});

export default rootReducer; 

配置商店的样子

import { isLoggedIn } from '../actions/auth';
import {createStore, compose, applyMiddleware} from 'redux';  
import { routerMiddleware } from 'react-router-redux';
import  rootReducer  from '../reducers/rootReducer';  
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory';
import ReduxPromise from 'redux-promise'


export const history = createHistory();

export function configureStore(initialState) {  
  const store = createStore(
        rootReducer,
        initialState,
        compose (
            applyMiddleware(thunk, ReduxPromise, routerMiddleware(history)),
            window.devToolsExtension ? window.devToolsExtension() : f => f
        )
  );

  if (module.hot) {
        // Enable Webpack hot module replacement for reducers
        module.hot.accept('../reducers/rootReducer', () => {
            const nextRootReducer = require('../reducers/rootReducer').default;
            store.replaceReducer(nextRootReducer);
        });
    }

    store.dispatch(isLoggedIn());
  return store;
}

initialState.js 看起来像这样。

import { isLoggedIn } from '../actions/auth';
import {createStore, compose, applyMiddleware} from 'redux';  
import { routerMiddleware } from 'react-router-redux';
import  rootReducer  from '../reducers/rootReducer';  
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory';
import ReduxPromise from 'redux-promise'


export const history = createHistory();

export function configureStore(initialState) {  
  const store = createStore(
        rootReducer,
        initialState,
        compose (
            applyMiddleware(thunk, ReduxPromise, routerMiddleware(history)),
            window.devToolsExtension ? window.devToolsExtension() : f => f
        )
  );

  if (module.hot) {
        // Enable Webpack hot module replacement for reducers
        module.hot.accept('../reducers/rootReducer', () => {
            const nextRootReducer = require('../reducers/rootReducer').default;
            store.replaceReducer(nextRootReducer);
        });
    }

    store.dispatch(isLoggedIn());
  return store;
}

对所有代码感到抱歉,但我觉得我一直在通过这些文件跟踪代码,但我不知道为什么它不起作用,因为我可以从 api 获取数据,无论是在需要身份验证时还是当它不是。 我想我犯了一个愚蠢的初学者错误,但如果有人能告诉我这个错误是什么,那将是非常棒的。

这是我创建应用程序和我在处理它时安装的其他模块所经历的过程。

run create-react-app
run insatll react-router-dom --save
run intstall auth0-lock --save
run install redux --save
run install redux-thunk --save
npm install redux-logger --save
npm install react-redux --save
npm install react-router-redux@next --save  //this needs to be v5 to be compatible with react-router-dom v4
npm install jwt-decode --save
npm install redux-promise --save
npm install history --save
npm install --save redux-form

感谢您的帮助..

【问题讨论】:

  • 有什么问题?道具不变?道具更改但组件不重新渲染?组件根本不渲染?
  • 嘿安德鲁,问题是在我完成登录后, (this.props.authenticated) 属性已更改,但标题不会重新呈现。完成登录后,标题应显示“注销”链接,但始终显示登录链接。

标签: reactjs authentication react-redux redux-thunk rerender


【解决方案1】:

我终于让它工作了。 这是我拥有的标题容器中的问题。

function mapStateToProps(state, ownProps) {  
  return {
    authenticated: state.authenticated
    }
}

函数应该是

function mapStateToProps(state, ownProps) {  
  return {
    authenticated: state.auth.authenticated
    }
}

我很想了解 state.auth 中 .auth 的来源... 目前我假设它来自包含此行的 auth reducer auth.js

export default function auth(state = initialState, action)

我为 phoneNumbers 准备的另一个 reducer 有

export default function phoneNumbers(state = initialState.phoneNumbers, action)

我可以从 state.phoneNumbers 访问 phoneNumber。 如果有人可以证实我的怀疑,或者将我指向正确的方向,那就太好了? 谢谢

【讨论】:

    猜你喜欢
    • 2018-04-09
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多