2016-09-16 42 views
1

我正在與React和Material玩Arround,並且我在如何在Material UI組件標籤中傳遞變量?允許物料UI中的變量RaisedButton標籤

這裏是我的代碼:

const LoginForm = ({ 
    myVariable 
}) => (
    {/*....*/} 
    <RaisedButton type="submit" label={myVariable} primary/> 
    {/*....*/} 
); 

LoginForm.propTypes = { 
    myVariable : PropTypes.string.isRequired 
}; 

export default LoginForm; 

但是,即便是在瀏覽器(鉻)正確顯示的標籤,控制檯告訴我這樣的警告:

warning.js:36 Warning: Failed prop type: Required prop label or children or icon was not specified in RaisedButton. 

編輯: 經過一些調試後,出現了多次呈現視圖(至少4次???),並且在第一次呈現中,myVariable未定義。

所以,現在,我必須管理爲什麼組件呈現幾次,爲什麼在第一次呈現中,變量是未定義的。

所以在這裏我的代碼。

Base.jsx

import React, {PropTypes} from 'react'; 
import {Link, IndexLink} from 'react-router'; 

const Base = ({ 
    children 
}) => (
    <div> 
    <div className="top-bar"> 
    {children} 
    </div> 
); 

Base.propTypes = { 
    children: PropTypes.object.isRequired 
}; 

export default Base; 

Auth.js

class Auth { 

    /** 
    * Authenticate a user. Save a token string in Local Storage 
    * 
    * @param {string} token 
    */ 
    static authenticateUser(token) { 
    localStorage.setItem('token', token); 
    } 

    /** 
    * Check if a user is authenticated - check if a token is saved in Local Storage 
    * 
    * @returns {boolean} 
    */ 
    static isUserAuthenticated() { 
    return localStorage.getItem('token') !== null; 
    } 

    /** 
    * Deauthenticate a user. Remove a token from Local Storage. 
    * 
    */ 
    static deauthenticateUser() { 
    localStorage.removeItem('token'); 
    } 

    /** 
    * Get a token value. 
    * 
    * @returns {string} 
    */ 

    static getToken() { 
    return localStorage.getItem('token'); 
    } 
} 

export default Auth; 

loginForm.jsx

import React, {PropTypes} from 'react'; 
import {Link} from 'react-router'; 
import {Card, CardText} from 'material-ui/Card'; 
import RaisedButton from 'material-ui/RaisedButton'; 
import TextField from 'material-ui/TextField'; 

const LoginForm = ({ 
    locales, 
    onSubmit, 
    onChange, 
    errors, 
    successMessage, 
    user 
}) => (
    <Card className="container"> 
    <form action="/" onSubmit={onSubmit}> 
     <h2 className="card-heading">{locales.connect_to_your_account}</h2> 

     {successMessage && <p className="success-message">{successMessage}</p>} 
     {errors.summary && <p className="error-message">{errors.summary}</p>} 

     <div className="field-line"> 
     <TextField 
      floatingLabelText={locales.email} 
      name="email" 
      errorText={errors.email} 
      onChange={onChange} 
      value={user.email} 
     /> 
     </div> 

     <div className="field-line"> 
     <TextField 
      floatingLabelText={locales.password} 
      type="password" 
      name="password" 
      onChange={onChange} 
      errorText={errors.password} 
      value={user.password} 
     /> 
     </div> 

     <div className="button-line"> 
     <RaisedButton type="submit" label={locales.log_in} primary/> 
     </div> 

     <CardText>{locales.dont_have_account_yet} <Link to={'/request-account'}>{locales.request_one}</Link>.</CardText> 
    </form> 
    </Card> 
); 

LoginForm.propTypes = { 
    locales  : PropTypes.object.isRequired, 
    onSubmit  : PropTypes.func.isRequired, 
    onChange  : PropTypes.func.isRequired, 
    errors  : PropTypes.object.isRequired, 
    successMessage: PropTypes.string.isRequired, 
    user   : PropTypes.object.isRequired 
}; 

export default LoginForm; 

loginPage.jsx

import React, {PropTypes} from 'react'; 
import Auth from '../modules/Auth'; 
import LoginForm from '../components/LoginForm.jsx'; 

class LoginPage extends React.Component { 

    /** 
    * Class constructor. 
    */ 
    constructor(props, context) { 
    super(props, context); 

    const storedMessage = localStorage.getItem('successMessage'); 
    let successMessage = ''; 

    if (storedMessage) { 
     successMessage = storedMessage; 
     localStorage.removeItem('successMessage'); 
    } 

    // set the initial component state 
    this.state = { 
     locales: {}, 
     errors : {}, 
     successMessage, 
     user : { 
     email : '', 
     password: '', 
     }, 
    }; 

    this.processForm = this.processForm.bind(this); 
    this.changeUser = this.changeUser.bind(this); 
    } 

    // Load translations via an Api Rest 
    componentDidMount() { 
    const data = { 
     connect_to_your_account: {}, 
     log_in     : {}, 
     email     : {}, 
     password    : {}, 
     dont_have_account_yet : {}, 
     request_one   : {}, 
    }; 
    const xhr = new XMLHttpRequest(); 
    xhr.open('post', '/app_test.php/api/fr/translations'); 
    xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 

    xhr.responseType = 'json'; 
    xhr.addEventListener('load',() => { 
     if (xhr.status === 200) { 
     this.setState({ 
      locales: xhr.response, 
     }); 
     } 
    }); 
    xhr.send(JSON.stringify(data)); 
    } 

    /** 
    * Process the form. 
    * 
    * @param {object} event - the JavaScript event object 
    */ 
    processForm(event) { 
    // prevent default action. in this case, action is the form submission event 
    event.preventDefault(); 

    // create a base64 encoded string 
    const credentials = window.btoa(`${this.state.user.email}:${this.state.user.password}`); 

    // create an AJAX request 
    const xhr   = new XMLHttpRequest(); 
    xhr.withCredentials = true; 
    xhr.open('post', '/app_test.php/api/fr/tokens'); 
    xhr.setRequestHeader('authorization', `Basic ${credentials}`); 

    xhr.responseType = 'json'; 
    xhr.addEventListener('load',() => { 
     if (xhr.status === 201) { 
     // success 

     // change the component-container state 
     this.setState({ 
      errors: {} 
     }); 

     // save the token 
     Auth.authenticateUser(xhr.response.token); 

     // change the current URL to/
     this.context.router.replace('/'); 
     } else { 
     // failure 

     // change the component state 
     const errors = xhr.response.errors ? xhr.response.errors : {}; 
     errors.summary = xhr.response.message; 

     this.setState({ 
      errors 
     }); 
     } 
    }); 
    xhr.send(null); 
    } 

    /** 
    * Change the user object. 
    * 
    * @param {object} event - the JavaScript event object 
    */ 
    changeUser(event) { 
    const field = event.target.name; 
    const user = this.state.user; 
    user[field] = event.target.value; 

    this.setState({ 
     user 
    }); 
    } 

    /** 
    * Render the component. 
    */ 
    render() { 
    return (
     <LoginForm 
     locales={this.state.locales} 
     onSubmit={this.processForm} 
     onChange={this.changeUser} 
     errors={this.state.errors} 
     successMessage={this.state.successMessage} 
     user={this.state.user} 
     /> 
    ); 
    } 

} 

LoginPage.contextTypes = { 
    router: PropTypes.object.isRequired 
}; 

export default LoginPage; 

routes.js

import Basepage from './containers/BasePage.jsx'; 
import LoginPage from './containers/LoginPage.jsx'; 
import Auth from './modules/Auth'; 

const routes = { 
    // base component (wrapper for the whole application). 
    component : Basepage, 
    childRoutes: [ 

    { 
     path  : '/', 
     getComponent: (location, callback) => { 
     if (Auth.isUserAuthenticated()) { 
      callback(null, DashboardPage); 
     } else { 
      callback(null, LoginPage); 
     } 
     } 
    }, 

    { 
     path  : '/login', 
     component: LoginPage 
    }, 

    { 
     path : '/logout', 
     onEnter: (nextState, replace) => { 
     Auth.deauthenticateUser(); 

     // change the current URL to/
     replace('/'); 
     } 
    } 

    ] 
}; 

export default routes; 

index.js(ACCES點)

import React from 'react'; 
import ReactDom from 'react-dom'; 
import injectTapEventPlugin from 'react-tap-event-plugin'; 
import getMuiTheme from 'material-ui/styles/getMuiTheme'; 
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 
import {browserHistory, Router} from 'react-router'; 
import routes from './routes.js'; 

import '../styles/main.scss'; 

// remove tap delay, essential for MaterialUI to work properly 
injectTapEventPlugin(); 

ReactDom.render((
    <MuiThemeProvider muiTheme={getMuiTheme()}> 
    <Router history={browserHistory} routes={routes}/> 
    </MuiThemeProvider>), document.getElementById('app') 
); 

我嘗試發送到視圖的變量都通過API休息翻譯文本檢索(譯文由後端管理)

感謝您的任何幫助。

+0

你代碼是無效的。據我所知它應該是'primary = {true}'。 myVariable的內容是什麼? –

+0

更正了設置primary = {true}的代碼,但它不會更改任何內容。 myVariable只是一些隨機字符串。 –

+0

據我所知'prop = {true}'和'prop'是等價的,都是有效的。 – Waiski

回答

0

我終於找到了workarround,不知道它的最佳做法或不:

label={`${myVariable}`} 
+0

它不是。如果您只是執行'label =「myLabel」'錯誤消失或? –

+0

是的,如果我使用'label =「myLabel」',錯誤消失了,但我不想直接設置文本,我想要一個變量文本。我如何使用React最佳實踐做到這一點?謝謝。 –

+0

我認爲這是因爲你所做的所有答案都是爲了滿足字符串的propType要求。第一個'render'可能是'myVariable'是'undefined'嗎?你應該真的添加你的完整代碼! –

0

您可以defaultProps嘗試,myVariable可能是undefined第一渲染

LoginForm.defaultProps= { 
    myVariable: "", 
}; 
+0

是的,這就像el solo lobo所說。但是現在我想知道爲什麼會有很多渲染(登錄頁面上至少有4個渲染)。我在原始問題中添加了完整的代碼。再次感謝。 –