I'm using AutobahnJS I don't know how to use the same connection in another component.
I decided to make it manually by passing the session argument to another component like this but that's doesn't work I don't know why
Main component:
class App extends Component {
componentWillMount(){
this.Call();
}
Call = () => {
var connection = new autobahn.Connection({ url: 'ws://127.0.0.1:9000/', realm: 'realm1' });
connection.onopen = function Pass (session) {
console.log(session, 'This I want to use it in anothr component')
};
connection.open();
}
render() {
return (
<div>
<Two Pass={this.Pass} />
</div>
)
}
}
export default App;
Child Component
class Two extends Component {
this.props.Pass(session); // if I console.log session will get error
//How to console log session here
render() {
return (
<div>
Child component
</div>
)
}
}
export default Two;
What is the best way to use the same connection(session) of Autobahn in another component?
update
class App extends Component {
constructor(props) {
super(props);
this.state = {
pageNumber: 1
}
this.sessionVar = this.sessionVar.bind(this)
}
Maybe you can try something like this:
let sessionVar = undefined
class App extends Component {
componentWillMount(){
this.Call();
}
Call = () => {
var connection = new autobahn.Connection({ url: 'ws://127.0.0.1:9000/', realm: 'realm1' });
connection.onopen = function Pass (session) {
console.log(session, 'This I want to use it in anothr component')
sessionVar = session
};
connection.open();
}
render() {
return (
<div>
<Two Pass={this.Pass} session={sessionVar} />
</div>
)
}
}
you can also use state and it will probably be easier that would look like this:
Call = () => {
var connection = new autobahn.Connection({ url: 'ws://127.0.0.1:9000/', realm: 'realm1' });
connection.onopen = function Pass (session) {
console.log(session, 'This I want to use it in anothr component')
this.setState({session})
};
connection.open();
}
render() {
return (
<div>
<Two session={this.state.session} />
</div>
)
}
}
Then you can do this in your child component:
class Two extends Component {
componentDidMount(){
console.log(this.props.session)
}
render() {
return (
<div>
Child component
</div>
)
}
}
export default Two;
Related
I have two js files, including login and sidebar.
In the login.js(class component), it will call the loginAction to perform an API call and get back response data(id, role, username).
import LoginAction from auth.js
...
handleSubmit(event) {
event.preventDefault();
var response = LoginAction(this.state)
}
LoginAction is in the auth.js
export function LoginAction(data) {
const loginName = data.loginName;
const password = data.password;
var response = Login(loginName, password).then(response => {
if (response.data.errorCode === "") {
sessionStorage.setItem("token", response.data.data.token)
return {passwordError: null, loginNameError: null, isLoggedOn: true, role: response.data.data.isAdmin};
} else {
return formatError(response.data);
}
})
return response;
};
Here is the Login which is in the authservice.js
export const Login = (loginName, password) => {
const postData = { loginName, password }
console.log(postData);
return Axios.post("http://localhost:8080/login", postData, header);
}
how to pass the response to sidebar.js(class component)? I want to display the user's role on the sidebar.
if (data.isLoggedOn) {
console.log("routing to /employee")
this.props.router.navigate("/employee", { state: { "id": id, "role": role } })
}
I have tried to use the state to pass the data, but the role cannot be loaded to the sidebar after the first loading. The role only displays when I load the sidebar page again.
You can create a state in a common parent component and pass down a function that sets that state. Here's a quick example where I define a state user in the App and define login() which sets its state. Then I pass login() as a prop to the login button, and pass user as a prop to the sidebar.
CodeSandbox
import React, { Component } from "react";
export default class App extends Component {
constructor(){
super();
this.state = {user: null}
}
login(user) {
this.setState({user})
}
render() {
return (
<div className="App">
<Login loginHandler={(user)=>this.login(user)}/>
<Sidebar user={this.state.user}/>
</div>
);
}
}
class Sidebar extends Component{
render(){
return(
<div className="sidebar">Hey {this.props.user}</div>
)
}
}
class Login extends Component{
render(){
return(
<button onClick={()=>this.props.loginHandler('Foo')}>Login</button>
)
}
}
When I set the array data using the function getData() then try to call it in the function updateData() I get an error saying the this.state.data is undefined. Any thoughts on how I can pass a this.state variable from one function to another function in the app context provider?
Example code is below:
Any thoughts? Thank you!
export class AppProvider extends React.Component {
constructor(props) {
super(props);
(this.state = {
data: [],
});
}
getData = async () => {
const data = "abc"
this.setState({
data,
});
}
updateData = async () => {
console.log(this.state.data)
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
);
}
}
Three Things i would like to say,
you want to add the state variables separately so you want to do value={{data:this.state.data}}
if you plan on using these functions in another component you want to add these functions to the value prop as well
remove the async from the functions since there is no Promise to be resolved
export class AppProvider extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
getData = () => {
const data = "abc";
this.setState({
data
});
};
updateData = () => {
console.log(this.state.data);
};
render() {
return (
<AppContext.Provider
value={{
data: this.state.data,
getData: this.getData,
updateData: this.updateData
}}
>
{this.props.children}
</AppContext.Provider>
);
}
}
checked this in a small example, CodeSandbox here
I want to keep some functions outside of my component for easier testing. However, I cannot change state with these functions because they cannot reference the component's state directly.
So I currently have the hacky solution where I set the function to a variable then call this.setState. Is there a better convention/more efficient way to do this?
Example function code in Tester.js:
const tester = () => {
return 'new data';
}
export default tester;
Example component code in App.js (without imports):
class App extends Component {
constructor() {
super();
this.state = {
data: ''
}
}
componentDidMount(){
let newData = tester();
this.setState({ data: newData })
}
render() {
return(
<div>{this.state.data}</div>
)
}
}
You could bind your tester function like this (this approach doesn't work with arrow functions):
function tester() {
this.setState({ data: 'new Data' });
}
class App extends Component {
constructor() {
super();
this.state = {
data: '',
};
this.tester = tester.bind(this);
}
componentDidMount() {
this.tester();
}
render() {
return (
<div>{this.state.data}</div>
);
}
}
But I would prefer a cleaner approach, where you don't need your function to access this (also works with arrow functions):
function tester(prevState, props) {
return {
...prevState,
data: 'new Data',
};
}
class App extends Component {
constructor() {
super();
this.state = {
data: '',
};
}
componentDidMount() {
this.setState(tester);
}
render() {
return (
<div>{this.state.data}</div>
);
}
}
You can pass a function to setState() that will return a new object representing the new state of your component. So you could do this:
const tester = (previousState, props) => {
return {
...previousState,
data: 'new data',
};
}
class App extends Component {
constructor() {
super();
this.state = {
data: ''
}
}
componentDidMount(){
this.setState(tester)
}
render() {
return(
<div>{this.state.data}</div>
)
}
}
The reason being that you now have access to your component's previous state and props in your tester function.
If you just need access to unchanging static placeholder values inside of your app, for example Lorem Ipsum or something else, then just export your data as a JSON object and use it like that:
// testData.js
export const testData = {
foo: "bar",
baz: 7,
};
...
// In your app.jsx file
import testData from "./testData.js";
const qux = testData.foo; // "bar"
etc.
I have the following class
class MatchBox extends React.Component {
constructor(props) {
super(props);
this.countdownHandler = null;
this.showBlocker = true;
this.start = this.start.bind(this);
}
start() {
...
}
render() {
...
return (
<div style={ styles.mainContainer } className="fluid-container">
...
</div>
);
}
};
function mapStateToProps(state) {
...
}
function matchDispatchToProps(dispatch) {
...
}
export default withRouter(connect(mapStateToProps, matchDispatchToProps, null, { withRef: true })(MatchBox));
which is used in this class
class GameBox extends React.Component {
constructor(props) {
super(props);
...
}
render() {
var mainElement = null;
switch(this.props.mainElement.element) {
case 'SEARCHING': mainElement = <SearchingBox gameType={ this.props.gameType }/>; break;
case 'MATCH': mainElement = <MatchBox ref='matchBox'/>; break;
default: mainElement = <SearchingBox/>;
}
return (
<div style={ styles.mainContainer } className="fluid-container">
{ mainElement }
</div>
);
}
};
function mapStateToProps(state) {
...
}
function matchDispatchToProps(dispatch) {
...
}
export default withRouter(connect(mapStateToProps, matchDispatchToProps, null, { withRef: true })(GameBox));
And I can't get the ref of the object MatchBox. I tried with this.refs.matchBox and is null, also tried getting directly from ref(ref={(r) => { // r is null } }) and I don't know what to try anymore.
I'm using react-router-dom 4 and I don't know if function withRouter affect the outcome component.
It's not pretty, but I think this is the solution. withRouter exposes the child ref via a wrappedComponentRef callback, which gets us to the connect hoc. That exposes its child ref via getWrappedInstance if you pass the withRef attribute as you did. So you just have to combine both of those.
class GameBox extends React.Component {
matchboxRefCallback = (connectHOC) => {
this.matchboxRef = connectHOC ? connectHOC.getWrappedInstance() : null;
}
render() {
return <MatchBox wrappedComponentRef={this.matchboxRefCallback}/>;
}
}
Much more cleaner solution would be to create a HOC. which will forward the ref to actual component
const matchBoxHOC = (WrappedComponent) => {
class MatchBoxHOC extends React.Component {
render() {
const { forwardRef, ...rest } = this.props;
return <WrappedComponent {...rest} ref={forwardRef} />;
}
}
const WithRouterMatchBoxHOC = withRouter(MatchBoxHOC, { withRef: true });
return React.forwardRef((props, ref) => {
return <WithRouterMatchBoxHOC {...props} forwardRef={ref} />;
});
}
Call is like
export default matchBoxHOC(connect(mapStateToProps, matchDispatchToProps, null, { withRef: true })(MatchBox));
I am trying to create a simple Inbox, that makes an api call and returns json object containing a list of messages. This is then passed via props down to the 'InboxList' and then 'InboxItem' components. However, I am struggling to get props down to render each item.
I am also receiving an error when using bind(this), which is the following.
index.js:28 Uncaught (in promise) TypeError: (intermediate value).bind is not a function(…)
I believe i need to bind within my componentDidMount method due to es6 syntax, but I do not understand what the error refers to. Fwiw the json data is coming back successfully.
Any leads on this would be most appreciated
export default class Inbox extends Component {
constructor() {
super();
this.state = {
messages: [],
};
}
componentDidMount() {
this.serverRequest = axios.get('/api/messages')
.then(res => {
console.log(res.data);
})
.catch(res => {
if (res instanceof Error) {
console.log(res.message);
} else {
console.log(res.data);
}
this.setState({
messages: res.data,
}.bind(this));
});
}
render() {
return (
<div>
<InboxHeader />
<InboxList messages={this.state.messages} />
</div>
);
}
}
export default class InboxList extends Component {
render() {
return (
<ul className="dm-inbox__list">
{this.props.messages.map(message =>
<InboxItem message={message} />
)}
</ul>
);
}
}
read this for more info http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
A fix for you below. no need to bind to the promise
https://www.toptal.com/javascript/10-most-common-javascript-mistakes
xport default class Inbox extends Component {
constructor() {
super();
this.state = {
messages: [],
};
}
componentDidMount() {
//serverRequest remove it
//this.serverRequest = axios.get('/api/messages')
axios.get('/api/messages')
.then((response)=>{
console.log(response);
if(response.status===200){
return response.data;
} else {
throw new Error("Server response wasn't ok");
}
})
.then((responseData)=>{
this.setState({messages:responseData});
}).catch((error)=>{
});
}
render() {
return (
<div>
<InboxHeader />
//the messages array might be still empty cause the network call is async so do a check in the inbox list
<InboxList messages={this.state.messages} />
</div>
);
}
}
export default class InboxList extends Component {
render() {
//check if null or empty if not yet resolved show loading eg spinner
if(!this.props.messages){
return <div>loading....</div>;
}
return (
<ul className="dm-inbox__list">
{this.props.messages.map(message =>
<InboxItem message={message} />
)}
</ul>
);
}
}
import React, {Component} from 'react';
export const fetchResource = msg => WrappedComponent =>
class extends Component {
constructor(props){
super(props);
this.state = {
resource: null,
msg: null
};
}
componentDidMount(){
this.setState({msg})
axios.get('https://api.github.com/users/miketembos/repos')
.then((response)=>{
console.log(response);
if(response.status===200){
return response.data;
} else {
throw new Error("Server response wasn't ok");
}
})
.then((responseData)=>{
this.setState({resource:responseData});
}).catch((error)=>{
this.props.history.pushState(null, '/error');
});
}
render(){
const {resource} = this.state
return <Posts {...this.props} {...resources } />
}
}