admin管理员组

文章数量:1394125

I e from vue.js, so I'm still a bit confused about react.

I have a Message ponent, that shows up flash messages:

import React, {Component} from "react";

export default class Message extends Component {

    constructor(props) {
        super(props);
        this.state = {messages: []};
    }

    setMessage(type, body) {
        this.setState({messages: this.state.messages.concat({type: type, body: body})})
        setTimeout(() => {
            this.removeMessage()
        }, 10000);
    }

    removeMessage() {
        let messages = this.state.messages;
        messages.shift();
        this.setState({messages: messages});
    }

    render() {
        return (
            <div className="uk-messages">
                {
                    this.state.messages.map((message, index) => {
                        if (message.type === 'error') {
                            message.type = 'danger';
                        }

                        return (
                            <div className={'uk-alert-' + message.type} data-uk-alert key={index}>
                                <p>{message.body}</p>
                            </div>
                        )
                    })
                }
            </div>
        )    
    }    
}

I use this ponent in my Index ponent:

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter as Router, Link, Route, Redirect} from 'react-router-dom'
import Auth from './helpers/auth'
import Message from './helpers/message'

class Index extends Component {
    constructor(props) {
        super(props);
        this.state = {
            authState: Auth.state,
        };
        Auth.initialize();    
    }

    render() {
        return (    
            <Router>
                <div className="uk-flex uk-flex-column">
                    <nav className="uk-navbar-container" data-uk-navbar>
                        <div className="uk-navbar-left">
                            <a className="uk-navbar-item uk-logo" href="#"><img src={'images/logo.png'}/></a>

                            <ul className="uk-navbar-nav">
                                <li><Link to="/">Home</Link></li>
                            </ul>
                        </div>
                        <div className="uk-navbar-right">
                            <ul className="uk-navbar-nav">
                                <li>
                                    <a href="#" className="uk-open" aria-expanded="true">
                                        <span data-uk-icon="icon: user" />
                                    </a>

                                </li>

                            </ul>
                        </div>
                    </nav>
                    <div className="uk-flex-grow-1">
                        <Route path="/" ponent={Wele} />
                    </div>
                    <footer>
                        &copy; 2018 stackoverflow
                    </footer>
                    <Message />
                </div>    
            </Router>
        );
    }

}

if (document.getElementById('root')) {
    ReactDOM.render(<Index/>, document.getElementById('root'));
}

Ok, so the Index ponent is the one I start with. I import the Message ponent and render it. That works. In chrome react console, I select the Message tag and can add some messages with

$r.setMessage('success','Greetings my old friend!')

The message appears. So now, how can I use the method setMessage in my Index ponent? In vue.js it's so simple (use $parent or $children)...

I e from vue.js, so I'm still a bit confused about react.

I have a Message ponent, that shows up flash messages:

import React, {Component} from "react";

export default class Message extends Component {

    constructor(props) {
        super(props);
        this.state = {messages: []};
    }

    setMessage(type, body) {
        this.setState({messages: this.state.messages.concat({type: type, body: body})})
        setTimeout(() => {
            this.removeMessage()
        }, 10000);
    }

    removeMessage() {
        let messages = this.state.messages;
        messages.shift();
        this.setState({messages: messages});
    }

    render() {
        return (
            <div className="uk-messages">
                {
                    this.state.messages.map((message, index) => {
                        if (message.type === 'error') {
                            message.type = 'danger';
                        }

                        return (
                            <div className={'uk-alert-' + message.type} data-uk-alert key={index}>
                                <p>{message.body}</p>
                            </div>
                        )
                    })
                }
            </div>
        )    
    }    
}

I use this ponent in my Index ponent:

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter as Router, Link, Route, Redirect} from 'react-router-dom'
import Auth from './helpers/auth'
import Message from './helpers/message'

class Index extends Component {
    constructor(props) {
        super(props);
        this.state = {
            authState: Auth.state,
        };
        Auth.initialize();    
    }

    render() {
        return (    
            <Router>
                <div className="uk-flex uk-flex-column">
                    <nav className="uk-navbar-container" data-uk-navbar>
                        <div className="uk-navbar-left">
                            <a className="uk-navbar-item uk-logo" href="#"><img src={'images/logo.png'}/></a>

                            <ul className="uk-navbar-nav">
                                <li><Link to="/">Home</Link></li>
                            </ul>
                        </div>
                        <div className="uk-navbar-right">
                            <ul className="uk-navbar-nav">
                                <li>
                                    <a href="#" className="uk-open" aria-expanded="true">
                                        <span data-uk-icon="icon: user" />
                                    </a>

                                </li>

                            </ul>
                        </div>
                    </nav>
                    <div className="uk-flex-grow-1">
                        <Route path="/" ponent={Wele} />
                    </div>
                    <footer>
                        &copy; 2018 stackoverflow.
                    </footer>
                    <Message />
                </div>    
            </Router>
        );
    }

}

if (document.getElementById('root')) {
    ReactDOM.render(<Index/>, document.getElementById('root'));
}

Ok, so the Index ponent is the one I start with. I import the Message ponent and render it. That works. In chrome react console, I select the Message tag and can add some messages with

$r.setMessage('success','Greetings my old friend!')

The message appears. So now, how can I use the method setMessage in my Index ponent? In vue.js it's so simple (use $parent or $children)...

Share Improve this question asked Jul 19, 2018 at 9:36 DaFunkyAlexDaFunkyAlex 1,9692 gold badges25 silver badges36 bronze badges 2
  • 2 I see answers popping up mentioning refs, but before you get excited about them, I remend you read reactjs/docs/refs-and-the-dom.html – Tom Fenech Commented Jul 19, 2018 at 9:42
  • Yeah you should avoid this bottom up dataflow in React and inverse it via passing messageArray to Message Component and handle this setMessage stuff in the Index – 42tg Commented Jul 19, 2018 at 9:48
Add a ment  | 

3 Answers 3

Reset to default 3

The most direct way to access the methods of another ponent is to pass refs, but you should probably approach the issue in a different way. Once you start tying your ponents together with refs, you make them less reusable and more difficult to work with.

If the list of messages were stored at a higher level, and passed into your Message ponent as a prop, then you would have no need for refs.

So I would remend moving messages into the state of the Index ponent (or possibly even to a store), then passing messages as a prop to <Message messages={this.state.messages} />.

If you also want to manipulate the messages from within the Message ponent, then also pass whatever callbacks from <Index> that you need.

Below is a toy example showing the general idea of storing the state in the parent ponent and passing messages and addMessage as props to <Message>.

const Message = ({ messages, addMessage }) => (
  <div>
    {messages.map(({ text, id }) => <div key={id}>{text}</div>)}
    <button onClick={addMessage}>add</button>
  </div>
);

class Index extends React.Component {
  constructor(props) {
    super(props);
    this.addMessage = this.addMessage.bind(this);
  }

  state = {
    messages: [],
    id: 0
  };
  
  addMessage() {
    this.setState({ 
      messages: [...this.state.messages, { text: "new message", id: this.state.id }],
      id: this.state.id + 1
    });
  }
  
  render() {
    return <Message messages={this.state.messages} addMessage={this.addMessage} />
  }
}

ReactDOM.render(<Index/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

You can use refs to get the reference to the element e.g.

<Message refs={(ref) => this.messageElement = ref }/>

With that you can call methods on it from anywhere after it has been assigned

this.messageElement.setMessage();

You can use refs (references) as

 <Message ref={(c) => this.messageComponent = c} />

and make functions of Message ponent with context bound so that it is accessible in other ponents like

Message Component

 constructor(props) {
        super(props);
        this.state = {messages: []};
        this.setMessage = this.setMessage.bind(this);
    }

Usage in Index ponent

  this.messageComponent.setMessage('type','body');

Read more of refs here

本文标签: javascriptreactjs call a function from another componentStack Overflow