There is a state and i want to update this state with in a function.
In function i declared a variable and i want to update state with this variable.
this.state = {
RequestData : [],
searchopen : false,
capturedImage : ""
}
screenShot = () => {
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
// Get base64URL
var base64URL = canvas.toDataURL('image/jpeg').replace('image/jpeg', 'image/octet-stream');
});
this.setState({capturedImage: base64URL})
}
You need to put setState in function that get base64URL and bind your screenShot function to use this.setState:
// constructor
constructor(props) {
super(props);
this.state = {
RequestData: [],
searchopen: false,
capturedImage: ""
}
this.screenShot = this.screenShot.bind(this);
}
screenShot = () => {
html2canvas(document.body).then(function (canvas) {
document.body.appendChild(canvas);
// Get base64URL
var base64URL = canvas.toDataURL('image/jpeg').replace('image/jpeg', 'image/octet-stream');
this.setState({ capturedImage: base64URL })
}.bind(this)); // bind here also
}
The problem here is you are doing the state update outside the callback function. Since this is a asynchronous task, your method will not work. Try this:
screenShot = () => {
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
// Get base64URL
var base64URL = canvas.toDataURL('image/jpeg').replace('image/jpeg', 'image/octet-stream');
this.setState({capturedImage: base64URL})
});
}
Not pretty but should work
this.state = {
RequestData : [],
searchopen : false,
capturedImage : ""
}
screenShot = () => {
var setState = newStore => this.setState((state, props) => ({ ...newStore })); // define the function outside
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
// Get base64URL
var base64URL = canvas.toDataURL('image/jpeg').replace('image/jpeg','image/octet-stream');
setState({capturedImage: base64URL}) // use here
});
}
Related
I am facing issue in adding chat message in my Flatlist because I am not able to call any function inside stompClient.subscribe ()
My code is as following :
dummy='dummyurl';
sock = new SockJS(this.dummy);
componentDidMount() {
var that = this;
this.sock.onConnect =(e) =>{
console.log("connected")
}
this.sock.onopen = function() {
console.log('open');
var dummy2='dummyurl';
var sock2 = new SockJS(dummy2);
let stompClient = Stomp.over(sock2);
stompClient.heartbeat.outgoing = 20000;
stompClient.heartbeat.incoming = 0;
stompClient.connect({}, (frame) => {
stompClient.subscribe('xyz/getChat', (messageOutput) =>{
var mymessage =JSON.parse(messageOutput.body).message;
this.state = {
incomingchatMessage: "",
chatMessages:[]
}
that.setState({incomingchatMessage:mymessage}) //getting issue setState not found
console.log(this.state)
});
});
};
this.sock.onmessage =(e) =>{
console.log('message', e);
alert("on message calledj")
};
this.sock.onmessage = evt => {
console.log("erve");
}
}
In this code I am able to get net message inside new_message variable but not able to update state value here .
Any solution of this condition .
why my log not showing anything ? is ths because the variable isLoading state ?
my code :
function getColumns(data) {
const columns = [];
const sample = data[0];
console.log("theSample" + sample);
and i call it from here :
class App extends React.Component {
constructor() {
super();
this.state = { isLoading: true };
if (this.state.isLoading === false) {
//const data = getData();
const data = this.state.dataExt;
// console.log(data);
const columns = getColumns(data);
this.state = {
data,
columns,
visible: false
};
}
}
Because, you only call getColumns when this.state.isLoading === false, and the initial value of your isLoading state is true. Therefore, unless you update your isLoading state, getColumns wouldn't be called and your log wouldn't show up.
I'm working on a react app base con create-react-app, the app works well on dev server but when I run the build something happen and the app not working.
I use a HOC with some function as context, the function declared in the context (HOC) not working because this is not declared.
Everything work fine on dev, if for test before the build I comment
this.getProducts();
on componentDidMount the problems move forward on the next function that use this.
Someone can help me? Thanks in advance.
const GlobalContext = React.createContext()
class GlobalProvider extends React.Component {
constructor(props) {
super(props)
this.loadingToggle = ( status = null, where = '' ) => {
// enable and disable loading
}
this.loginFunction = (e, utente_id, password) => {
// rest api login
}
this.logoutFunction = () => {
// logout
}
this.getProducts = () => {
this.forceUpdate();
this.loadingToggle(true, "getProducts");
// HERE THE PROBLEMS
var _this = this;
axios.post(Config.apiBaseUrl + '/users/products', {
token: localStorage.getItem('token')
})
.then( (response) => {
if (response.data.success !== true ){
// user not exist
}else{
// populate user data
// HERE I USE _this
}
})
.catch(function (error) {
// catch error
});
}
this.cartVariation = (id, qty, minQty = 0) => {
// cart action
}
this.sendOrder = (addressId) => {
// send order
}
this.state = {
isAuth: false,
loginFunction: this.loginFunction,
logoutFunction: this.logoutFunction,
cartVariation: this.cartVariation,
removeCart: this.removeCart,
cart: null,
forceUpdate: this.forceUpdate,
lastUpdate: new Date().getTime(),
cartCount: JSON.parse(localStorage.getItem("mf-cart")) !== null ? Object.keys( JSON.parse(localStorage.getItem("mf-cart"))).length : 0,
loadingToggle: this.loadingToggle,
loading: false,
store : {
mf_product_list : [],
mf_categories : [],
mf_users : [],
mf_users_formatted : [],
mf_backorders : [],
mf_backorders_list : [],
mf_address : []
},
sendOrder: this.sendOrder
}
}
componentDidMount () {
if (localStorage.getItem('token') !== null && localStorage.getItem('token-timestamp') !== null ){
this.setState({isAuth : true});
}
this.getProducts();
}
render() {
return (
<GlobalContext.Provider
value={{
isAuth: this.state.isAuth,
authToken: null,
loginFunction: this.state.loginFunction,
logoutFunction: this.state.logoutFunction,
cartVariation: this.state.cartVariation,
removeCart: this.state.removeCart,
cart: null,
forceUpdate: this.state.forceUpdate,
lastUpdate: this.state.lastUpdate,
cartCount: this.state.cartCount,
loading: this.state.loading,
store: this.state.store,
sendOrder: this.sendOrder
}}
>
{this.props.children}
</GlobalContext.Provider>
)
}
}
const GlobalConsumer = GlobalContext.Consumer
export { GlobalProvider, GlobalConsumer }
Change the function binding from Class properties
this.getProducts = () => {
// ...
}
to bind it in the constructor (ES2015)
constructor(props) {
// ...
this.getProducts = this.getProducts.bind(this);
}
More information about function binding is here.
I am new to React, so I know I might not be doing everything right.
I am trying to call setStatus inside of a callback for onreadystatechange but getting an error in the browser. The code does an AJAX call to the server to see if a proposed username is already in the database. Upon return the onreadystatechange is executed. There I am trying to set the new error message for the username if it already exists.
Here is my state data:
const initialState = {
firstname: "",
lastname: "",
username: "",
password: "",
email: "",
firstnameError: "",
lastnameError: "",
usernameError: "",
passwordError: "",
emailError: ""
};
class SignUpForm extends Component {
constructor() {
super();
this.state = initialState;
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.checkUserName = this.checkUserName.bind(this);
this.checkEmail = this.checkEmail.bind(this);
this.validateForm = this.validateForm.bind(this);
}
This is where I update state in a change handler for fields in the form:
handleChange(e) {
let target = e.target;
let value = target.value;
let name = target.name;
if (name === "username") {
value = value.toUpperCase();
}
this.setState({
[name]: value
});
}
This is the routine where I am getting an error in the browser. The lines where the error occurs is marked with a comment on the line below.
checkUserName() {
let usernameError = "";
let element = "";
let checkNameResponse = "";
let checkNameMessage = "";
let request = "";
let url = "";
let userName = "";
let requestData = "";
let checkNameResponseJSON = "";
request = new XMLHttpRequest();
if (request == null) alert("Unable to create checkDBForUSerNameRequest");
else {
url = "/php/CheckUsername.php";
userName = escape(document.getElementById("username").value);
requestData = JSON.stringify({
username: userName
});
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
checkNameResponseJSON = JSON.parse(request.responseText);
checkNameResponse = checkNameResponseJSON.returncode;
checkNameMessage = checkNameResponseJSON.message;
element = document.getElementById("SignupIcon");
element.className = "displayIcon";
if (checkNameResponse === 0) {
element = document.getElementById("SignupIconFile");
element.src = "/images/YesButton.png";
element.alt = "Available";
this.setState({ usernameError: "" });
} else {
element = document.getElementById("SignupIconFile");
element.src = "/images/NoButton.png";
element.alt = "Not Available";
usernameError = checkNameMessage;
this.setState({ usernameError: usernameError }); // BROWSER ERROR
}
}
};
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/json");
request.send(requestData);
}
}
This is the text from the browser error:
0: Object doesn't support property or method 'setState'
Any ideas why this happens or how to fix?
The error is because you are using request.onreadystatechange = function() {} instead of request.onreadystatechange = () => {} or request.onreadystatechange = function() {}.bind(this)
When you use function(), the scope of this changes.
Remember that function() {} and () => {} are not the same.
but function(){}.bind(this) and () => {} are the same.
You need to bind the onreadystatechange function using .bind or arrow function since when the function is executed it needs to access the correct this value referring to the class context.
request.onreadystatechange = function() {
// all logic here
}.bind(this)
or
request.onreadystatechange = () => {
//all logic here
}
i have a method set_data which is used to set data based on id. I know it could be easy to call this set_data in componentdidupdate when id changes. However in doing so it doesnt set some state variables in the parent component.
To get rid of that want to call set_data method in render . However since this set_data method sets state of data it enters into an infinite loop in render . Also cannot provide a condition (like prevprops.id!== this.props.id) to execute set_data method.
To prevent it thought of using this set_data method not to set state at all. and can call this set_data method in render.
Below is the code,
export default class child extends React.Component {
state = {
query: '',
data: null,
};
empty_id = 0xffffffff;
componentDidMount() {
this.set_open_data();
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.set_data();
}
}
set_data = () => {
if (!this.props.info) {
return;
}
if (this.props.id === this.empty_id) {
this.setState({data: null});
return;
}
let data = {
info: [],
values: [],
};
const info = this.props.info;
for (let i=0, ii=info.length; i < ii; i++) {
if (info[i].meshes.includes(this.props.id)) {
const info = info[i].info;
const values = info[i].values;
data = {
info: typeof info === 'string' ? info.split('\r\n') : [],
values: values ? values : [],
};
break;
}
}
this.setState({data: this.filter_data(data, this.state.query)});
};
render = () => {
const shown_data= this.state.data;
/* i want to call set_data method here*/};}
Could someone help me solve this. Thanks.
You can't call setData there, because that would be anti-pattern. It will trigger a loop that will continuously render as well as keeps setting state.
You can probably rewrite the component this way:
export default class child extends React.Component {
state = {
query: ''
};
empty_id = 0xffffffff;
componentDidMount() {
this.set_open_data();
}
set_data = () => {
let data = {};
if (!this.props.info) {
return data;
}
if (this.props.id === this.empty_id) {
return data;
}
let data = {
info: [],
values: [],
};
const info = this.props.info;
for (let i=0, ii=info.length; i < ii; i++) {
if (info[i].meshes.includes(this.props.id)) {
const info = info[i].info;
const values = info[i].values;
data = {
info: typeof info === 'string' ? info.split('\r\n') : [],
values: values ? values : [],
};
break;
}
}
data = this.filter_data(data, this.state.query);
return data;
};
render = () => {
const shown_data= this.state.data;
const data = this.set_data();
/* i want to call set_data method here*/};}
In this, we are not setting data in the state. For every new ID, it will get new data and will compute it from render thereby avoiding antipattern. I have also removed componentDidMount, since we are doing computation in render. Note: This solution means taking away data from the state, if you are not using data anywhere before render, this will work.
Let me know if this helps.