Below is my signup function in React. How can I render the errors it recieves from backend ? I tried to put a this.setResponse into the catch part ... that didn't work. I understand that componentWillReceiveProps should handle updates but this is an update from a Service (also below) not from a parent component.
If I print the err I can see a dictionary with errors, but I don't see how to pass them to the form or to the fields for rendering.
signup(evt) {
evt.preventDefault();
...
Auth.signup(dict)
.catch(function(err) {
alert("There's an error signing up");
console.log(err.response);
});
},
The Auth service is defined like this:
signup(dict) {
console.log(dict);
return this.handleAuth(when(request({
url: UserConstants.SIGNUP_URL,
method: 'POST',
type: 'json',
data: dict
})));
}
And I hoped to send errors to the fields with the following:
<UserNameField
ref="username"
responseErrors={this.responseErrors}
/>
Presuming that UserNameField is in the same component as the auth callback you can just set the state which will trigger a re-render and pass the values through UserNameField as props.
signup(evt) {
evt.preventDefault();
...
Auth.signup(dict)
.catch((err) => {
alert("There's an error signing up");
console.log(err.response);
this.setState({error: err});
});
},
<UserNameField
ref="username"
responseErrors={this.responseErrors}
error={this.state.error}
/>
This is the same as .bind(this).
Related
I'm working with a nice chatbot program for React someone wrote, and the thing is, you can actually bind the bot's responses to function calls like this:
render() {
const { classes } = this.props;
return (
<ChatBot
steps={[
{
...
{
id: '3',
message: ({ previousValue, steps }) => {
this.askAnswer(previousValue)
},
end: true,
},
]}
/>
);
Where message is the answer of the bot that it calculates based on the previousValue and askAnswer is a custom function you'd write. I'm using an API that inputs the previousValue to a GPT model, and I want to print the response of this API.
However, I just can't wrap my head around how I could pass the response of the API to the message. I'm trying this:
constructor(props) {
super(props);
this.state = { response: " " };
}
...
askAnswer(question) {
var jsonData = { "lastConversations": [question] }
fetch('http://my_ip:80/query', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jsonData)
}).then(response => response.json())
.then(data => { this.setState({ response: data["botResponse"] }) });
return (this.state.response)
}
I've been struggling with this for the past 2-3 hours now.
I've tried a couple of combinations, and nothing seems to work:
If I do as seen above, it seems like this.state.response just won't get
updated (logging data["botResponse"] shows there is a correct
reply, so the API part works and I get the correct response).
If I try async-await for askAnswer and the fetch call, then I can
only return a Promise, which is then incompatible as input for the
ChatBot message.
If I do not await for the fetch to complete, then
this.state.response just stays the default " ".
If I return the correct data["botResponse"] from within the second .then after the fetch, nothing happens.
How am I supposed to get the API result JSON's data["botResponse"] text field out of the fetch scope so that I can pass it to message as a text? Or, how can I get a non-Promise string return after an await (AFAIK this is not possible)?
Thank you!
In your last 2 line
.then(data => { this.setState({ response: data["botResponse"] }) });
return (this.state.response)
You are updating the state and trying to read and return the value in the same function which I think will never work due to async behaviour of state. (this is why your this.state.response in the return statement is the previous value, not the updated state value).
I'm not sure but you can write a callback on this.setState and return from there, the callback will read the updated state value and you can return the new state.
I am trying to implement a interceptor with axios so everytime I receive a response from a request, it checks if it has the field "msg" and if it has, it should show the message to the user.
To do this, I implemented a interceptor in axios, this interceptor should fire an event everytime it receives a response, then the App.js would be listening to this events to show the appropriate message.
My problem is that it seems the event is being fired twice, at first I though it was a problem with PubSub, which is the library that I was using, so I decided to try another framework (eventemitter3) and the exact same thing happened, so I'm totally lost, other people who had similar issues found out that their requests werte actually being fired twice by different components, I'm almost sure that this isn't the problem here, look at the logs when I make a request:
interceptor > Object { data: {…}, status: 200, statusText: "OK", headers: {…}, config: {…}, request: XMLHttpRequest }
intercepted by eventemitter3 > Object { data: null, msg: "Usuário não encontrado", success: true }
intercepted by eventemitter3 > Object { data: null, msg: "Usuário não encontrado", success: true }
intercepted by pubsub > Object { data: null, msg: "Usuário não encontrado", success: true }
intercepted by pubsub > Object { data: null, msg: "Usuário não encontrado", success: true }
notice that there is one "interceptor" log, which means only one request was intercepted, then one event is fired for eventemitter3 and one event is fired for pubsub. The networks tab of the browser only shows one POST and one OPTIONS request. Here is my axiosInstance:
import Axios from 'axios';
import PubSub from 'pubsub-js'
import Emitter from './EventHandler';
export const axios = Axios.create({
baseURL: "http://localhost/api"
})
axios.defaults.headers.common['Authorization'] = localStorage.getItem('jwt') || "";
axios.interceptors.response.use(function (response) {
console.log("interceptor",response)
Emitter.emit('RESPONSE_INTERCEPTED', response.data);
PubSub.publish('RESPONSE_INTERCEPTED', response.data);
return response;
}, function (error) {
return Promise.reject(error);
});
and here is App.js where I listen to the events:
export default function App() {
const alert = useAlert()
Emitter.on('RESPONSE_INTERCEPTED', (data) => {
console.log("intercepted by eventemitter3", data)
alert.show(data.msg)
});
var responseNotifier = function (msg, data) {
if(data.msg){
console.log("intercepted by pubsub", data)
}
};
var token = PubSub.subscribe('RESPONSE_INTERCEPTED', responseNotifier);
return (
<Router>
<div>
<Switch>
<Route path="/sobre"><Sobre /></Route>
<Route path="/memorias"><Memorias /></Route>
<Route path="/login"><Login /></Route>
</Switch>
</div>
</Router>
);
}
just in case it matters, here is the EventHandler for eventemitter3:
import EventEmitter from 'eventemitter3';
const eventEmitter = new EventEmitter();
const Emitter = {
on: (event, fn) => eventEmitter.on(event, fn),
once: (event, fn) => eventEmitter.once(event, fn),
off: (event, fn) => eventEmitter.off(event, fn),
emit: (event, payload) => eventEmitter.emit(event, payload)
}
Object.freeze(Emitter);
export default Emitter;
and the piece of code that makes the request:
login(){
axios.post('/login', {
"username": this.state.username,
"password": this.state.password
}).then((resp)=>{
// console.log(resp)
})
}
I'm really clueless here, everything I found on SO/Google points to requests being fired twice, but the whole application is still in the begining, the code aboce is the only plaec where I fire a request, and the network tab confirms this, I'm fine using whatver event framework or even a completely different solution, I just need to show the message to the user, if someone can point me what I'm doing wrong here It would be of great help for me. Thank you all!
The problem here is not the event firing twice, but being listened twice.
var token = PubSub.subscribe('RESPONSE_INTERCEPTED', responseNotifier);
this piece of code is running twice, probably because the component re-renders (not sure on this though) so everytime an event is fired once, there are two listeners to it doing the exact same thing. You can fix this by using the hook componentDidMount to add your listener. Since you are using a functional component, you can do it like this:
useEffect(()=>{
var token = PubSub.subscribe('RESPONSE_INTERCEPTED', responseNotifier);
})
I have a Metamask payment that works fine. It's triggered by an onClick of a button. I want to show something to the user during the pending of the transaction, but I can't figure out how since the promise returned is already the mined transaction. This is the code:
web3js.eth.sendTransaction({
to: '0x6Dc8956E655Ccd80187265107b848D8c5B6d2459',
from: address,
})
.then(function (txHash) {
console.log(txHash);
}).catch(error => {
console.log(error);
});
})
you need to use the state of your component
In constructor:
this.state = {willShowLoader: false}
In your onclick function (the second parameter is the callback)
this.state.setState({willShowLoader: true}, sendTransaction)
In your send transaction function: (note the setState inside of then)
web3js.eth.sendTransaction({
to: '0x6Dc8956E655Ccd80187265107b848D8c5B6d2459',
from: address,
})
.then(function (txHash) {
this.setState({willShowLoader:false})
console.log(txHash);
}).catch(error => {
console.log(error);
});
})
Then in your render method: (using conditional rendering)
(this.state.willShowLoader)?<Spinner/>:<notSpinner/>
I'd like to create component - - so that only authorised users can access it. the idea is that after receiving response 200 from backend in my Login component (which is a child component) I would somehow use authed:true as props in parent component. I understand this instructions https://reactjs.org/docs/lifting-state-up.html and also used similar procedure on other components. However, in this case, I am getting the error:
TypeError: this.props.authAfter200 is not a function
at Login.handleSetAuthAfterVerified200 (AuthExample.js:325)
at AuthExample.js:350
at <anonymous>
The problem is I am not able to define function as a prop in my child component.
This is the function in my parent component that should get called as a prop.
setAuthToTrue=() => {
this.setState({authed:true})
}
but I never get to here.
This is how I have defined my Route router in AuthExample(parent) component - using react-router-with-props for that:
<PrivateRoute
exact
path="/private"
redirectTo="/login"
component={DailyNewsForUOnly}
text="This is a private route"
authAfter200={this.setAuthToTrue}
authed={this.state.authed}
/>
this is the part in my child component - Login.js where I should be able to define function on my props to pass to the parent component - but I just cannot:
handleSetAuthAfterVerified200() {
//this.setState({authed:true})
this.props.authAfter200()
}
verifyToken() {
let request = {
method: "post",
url: "https://xxxxxx/xxxx/verify/",
data: {
user: this.state.email,
token: this.state.token
},
withCredentials: true
};
console.log("request to verify");
console.log(request);
this.setState({ requestInMotion: true });
axios(request)
.then(response => {
console.log("response from verify", response);
if (response.status === 200) {
this.handleSetAuthAfterVerified200()
this.setStateAfterVerified200()
}
})
.catch(error => {
console.log(error);
this.setState({ requestInMotion: false, validationState: "error" });
console.log(
"this.state in the error part of response in verify",
this.state
);
});
}
i would suggest u to try to add debuggers in
react-router-with-props/PrivateRoute.js and in
react-router-with-props/renderMergedProps.js
and check if your props are actually being passed on properly.
he is doing very simple job of either allowing react to render your component or to redirect to url provided as prop.
I would suggest you rather use HigherOrderComponents or OnEnter route hook to handle these situations than a third party component.
I'm new to ReactJs and I'm trying to bind a http response to the DOM, but I can't get it to work. Im using componentDidMount to execute the api call. Any help will be much appreciated, please see code below.
var testStuff="First State";
var Test = React.createClass({
loadTestData: function () {
$.ajax({
url: "http://localhost:64443/api/articles/apitest",
type: 'GET',
cache: false,
dataType: 'json',
success: function (response) {
console.log(response);
testStuff= response;
},
error: function (error) {
alert(error);
}
});
},
componentDidMount() {
this.loadTestData();
},
render() {
console.log(this.testStuff);
return (
<div onClick={this.loadTestData}>
{testStuff}
</div>
);
}
});
ReactDOM.render(
<Test />,
document.getElementById('content')
);
The onClick seems to be working, but its almost like the componentDidMount only gets executed after the page is rendered.
You need to properly update the component state in the AJAX success handler: this.setState({ testStuff: data })
Then you will be able to access it in render using this.state.testStuff.
componentDidMount indeed only runs after component has been mounted. You will also need to represent the UI state where the requests is still ongoing (this.state.testStuff will be undefined at that point).