如何在我的组件首次渲染时更新菜单状态?

时间:2017-10-13 17:07:01

标签: reactjs components render lifecycle

我有一个用参数调用的应用程序。现在,我的菜单总是加载到默认的MainMenu。我希望能够将状态传递给Menu.js并以打开的其他菜单开始,而不是默认的MainMenu。

我认为componentWillMount()可以让我将状态设置为我选择的菜单状态,但无论出于何种原因,它都不会更新渲染的内容。当我调用它时,this.state.Selected成为我想要呈现的正确菜单名称......但它实际上没有呈现 - 它最终呈现默认菜单。

所以我必须在componentWillMount()之后调用其他东西才能让它实际呈现?

Landing.js - 调用Menu.js.我想首先渲染菜单'FileOptions'。但是,它目前正在渲染MainMenu。

import React, { Component } from 'react'
import sass from '../scss/application.scss'
import PropTypes from 'prop-types'
import Header from './Header'
import Menu from './Menu'
import HelpFile from './HelpFile'



class Landing extends Component {
    constructor(props) {
         super(props);
         this.state = { 
             helpFileName: 'Mainmenu',
             menuName: 'FileOptions',
         }
       }

    handleHelpChange(helpFileName) {
        this.setState( {helpFileName} );
    }

    handleMenuClick(menuName) {
        this.setState( {menuName} );
    }

    componentWillMount() {
        let hlpString = require('electron').remote.getGlobal('sharedObject').hlpOne;
        if (hlpString != null && hlpString != '.')
        {
            this.setState({
                helpFileName: hlpString
            });ss
        }
    }

    render() {  

        return (
            <div>
                <div>
                    <Header />
                </div>
                <br /><br />
                <div className="mainMenuDiv">
                    <Menu handleHelpChange={this.handleHelpChange.bind(this)} menuName={this.state.menuName}/>
                </div>
                <div className="mainContainerDiv">
                    <HelpFile name={this.state.helpFileName}/>
                </div>
            </div>

        )
    }
}


export default Landing;

Menu.js

import React, { Component } from 'react'
import sass from '../scss/application.scss'
import PropTypes from 'prop-types'



class Menu extends Component {
    constructor(props) {
         super(props);
         this.state = { 
             Selected: props.menuName,      // reads FileOptions, but still renders MainMenu
             name: ''
         }
       }

    handleChange(name) {
        this.setState({
            name: name
        });
    }

    handleClick(e, num) {
        this.setState({
            name: num
          }, () => {
            let helpFileName = num;
            helpFileName = helpFileName.toLowerCase().trim();
            //Cap the first letter in the name and add the rest of the name 
            helpFileName = helpFileName.charAt(0).toUpperCase() + helpFileName.substr(1);
            this.props.handleHelpChange(helpFileName);
          });
      }

     handleMenuClick(e, num, opt) {
        this.setState({
            name: num,
            Selected: opt
          }, () => {
            let helpFileName = num;
            helpFileName = helpFileName.toLowerCase().trim();
            //Cap the first letter in the name and add the rest of the name 
            helpFileName = helpFileName.charAt(0).toUpperCase() + helpFileName.substr(1);
            this.props.handleHelpChange(helpFileName);
          });
      }

    render() {
        const MainMenu = () => (
            <div>
                <button 
                    label="File Options"
                    //onClick={() => this.setState({ Selected: FileOptions })} 
                    onClick={(e) => this.handleMenuClick(e, 'Fileopt', FileOptions)}
                    className="aMenuButton"
                >FILE OPTIONS</button>
                <button 
                    label="Setup Options"
                    onClick={(e) => this.handleMenuClick(e, 'Setupopt', SetUpOptions)}
                    className="aMenuButton"
                >SETUP OPTIONS</button>
                <button 
                    label="Lumber Options"
                    onClick={(e) => this.handleMenuClick(e, 'Lumberopt', MoreOptions)}
                    className="aMenuButton"
                >MORE OPTIONS</button>
                <button 
                    label="Main Menu"
                    onClick={(e) => this.handleClick(e, 'Mainmenu')} 
                    className="aPrevButton"
                >MAIN MENU</button>
            </div>
        );

        const FileOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Option Four"
                    onClick={(e) => this.handleClick(e, 'Option Four')}
                    className="aMenuButton"
                >Option Four</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const SetUpOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const MoreOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Option Four"
                    onClick={(e) => this.handleClick(e, 'Option Four')}
                    className="aMenuButton"
                >Option Four</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const { Selected } = this.state;

        return (
            <div>   
                <div className="menuButtons">
                    {Selected === 'MainMenu' ? <MainMenu /> : <Selected /> }
                </div>
            </div>
        )
    }
}

Menu.propTypes = {  
    handleHelpChange: PropTypes.func,
    name: PropTypes.string,
    menuName: PropTypes.string
}


export default Menu;

1 个答案:

答案 0 :(得分:1)

来自react docs for componentWillMount

  在安装发生之前立即调用

componentWillMount()。   它在render()之前调用,因此同步设置状态   在这种方法中不会触发重新渲染。避免引入任何   此方法中的副作用或订阅。这是唯一的   生命周期钩子在服务器渲染上调用。一般来说,我们建议   改为使用constructor()

更新1

在构造函数中设置所选的菜单名称,并从componentWillMount中删除setState。

更新2

@Yiou注意到<Selected />不是组件。

class Menu extends Component {
    constructor(props) {
      super(props);
      this.state = { 
        Selected: props.menuName || '',
        name: ''
      }
    }

  // ....

  render() {

    // after you created all your menu constant implement a switch to select
    // which menu is going to render
    const { Selected } = this.state;
    let SelectedMenu;
    switch(Selected) {
      case 'MainMenu':
        SelectedMenu = MainMenu;
        break;
      case 'FileOptions':
        SelectedMenu = FileOptions;
        break;
      default:
        SelectedMenu = MainMenu;
        break;
    }

    return (
        <div>   
            <div className="menuButtons">
                {SelectedMenu()}
            </div>
        </div>
    )
  }    
}