How to log both prevState and original state in React? - javascript

I have a toggle switch that goes from true to false.
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}))
}
Everything is working like it is supposed to, but I want to log both the prevState and original state at the same time. I tried below adding a callback function after setting the prevState, but then it breaks my toggle switch.
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}, () => console.log(prevState)))
}

Thats not correct what you're trying to do at here
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}, () => console.log(prevState)))
}
You won't have access to prevState in 2nd parameter of setState.
You should modify your setState function like this
flipSwitch = () => {
console.log(this.state) // this refers to previous state here
this.setState(prevState => {
console.log(prevState) // prevState refers to previous state
return ({
isToggleOn: !prevState.isToggleOn
})
}, () => console.log(this.state) // here this refers to updated state)
}
E.g you can try
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
isToggleOn: false
};
}
flipSwitch = () => {
console.log(this.state);
this.setState(
prevState => {
console.log("prevState", prevState);
return {
isToggleOn: !prevState.isToggleOn
};
},
() => {
console.log("setState Callback", this.state);
}
);
};
render() {
return (
<div className="App">
<button onClick={this.flipSwitch}>
{this.state.isToggleOn ? "Flipped" : "Flip Switch!"}
</button>
</div>
);
}
}
export default App;

Related

REACT, Help me understand prevState

What is the difference between defining this counterHandler like this
counterHandler = () => {
this.setState(() => {
return { times: this.state.times + 1 }
});
}
And this?
counterHandler = () => {
this.setState((prevState) => {
return { times: prevState.times + 1 }
});
}
Does the state from a component always gets passed to setState automatically?
If you only use One data inside state, you dont need to make callback of prevState,
but if your state more than one, you need to callback of prevstate because this will make your other and previous data will not be lost.
for example
const [state, setState] = useState({
loading: false,
data: []
})
const handleLoading = () => {
setState({
loading: true
})
}
const handleData = () => {
setState({
data: [a,b,c] // you will lost your loading = true
})}
const handleData = () => {
setState((prevState) => {
...prevState,
data: [a,b,c] // you still have loading = true
})
}

Updating a single item in React context state

So I have a Context of the following format:
class UserProvider extends Component {
constructor(props) {
super(props)
this.initialize = (details) => {
this.setState(state => {
//Setting each item individually here
//e.g state.a = details.a
})
}
this.editA = () => {
this.setState(state => {
//change A here
})
}
this.editB = () => {
this.setState(state => {
//Change B here
})
}
this.state = {
a: null,
b: null,
editA: this.editA,
editB: this.editB
}
}
render() {
return (
<User.Provider value={this.state}>
{this.props.children}
</User.Provider>
)
}
}
So for each state, I have a separate function to update it. If I want to update only a single state, what should I do?
Consider implementing a generic function so that you can control your key and the corresponding value.
i.e.
const changeField = (key, value) => this.setState({ [key]: value});
Function call
changeField('a','value_a')
changeField('b','value_b')

Kick off a function when two properties in state are set

I'm new to React JS and am slowly blundering my way along but hit an issues I figured I'd ask about here.
I have a component that is a container of the state and all the data I care about
class PirateContainer extends Component {
constructor(props) {
super(props);
this.state = {
PirateCaptains: [],
Year: [],
Ship: [],
PirateChoices: {
SelectedYear : "",
SelectedPirateCaptain : "",
SelectedShip : ""
}
};
this.handleYearChange = this.handleYearChange.bind(this);
this.handleShipChange = this.handleShipChange.bind(this);
this.handlePirateCaptainChange = this.handlePirateCaptainChange.bind(this);
}
popYear(accessLevel){
fetch('https://Pirateman/api/Years').then(response => {
return response.json();
})
.then((json) => {
this.setState(
prevState => ({
Year: json,
Choices: {
...prevState.PirateChoices,
SelectedYear: json[0]
}
}), () => {
console.log(this.state);}
);
});
}
popCaptain({
fetch('https://Pirateman/api/PirateCaptains').then(response => {
return response.json();
})
.then((json) => {
this.setState(
prevState => ({
PirateCaptain: json,
PirateChoices: {
...prevState.PirateChoices,
SelectedPirateCaptain: json[0]
}
}), () => {console.log(this.state);}
);
});
}
popShip(year, captain){
fetch('https://Pirateman/api/Ships/' + year + '/' + captain ).then(response => {
return response.json();
})
.then((json) => {
this.setState(
prevState => ({
Ship: json,
PirateChoices: {
...prevState.PirateChoices,
SelectedShip: json[0]
}
}), () => {console.log(this.state);}
);
});
}
handleYearChange(e) {
let value = e.target.value;
if(this.state.PirateChoices.SelectedYear === value)
{
console.log('Do nothing')
}
else
{
this.setState(
prevState => ({
PirateChoices: {
...prevState.PirateChoices,
SelectedYear: value
}
}), () => {console.log(this.state)}
);
}
}
handlePirateCaptainChange(e) {
let value = e.target.value;
if(this.state.PirateChoices.SelectedPirateCaptain === value)
{
console.log('Do nothing')
}
else
{
this.setState(
prevState => ({
PirateChoices: {
...prevState.PirateChoices,
SelectedPirateCaptain: value
}
}), () => {console.log(this.state)}
);
}
}
handleShipChange(e) {
let value = e.target.value;
if(this.state.PirateChoices.SelectedShip === value)
{
console.log('Do nothing')
}
else
{
this.setState(
prevState => ({
PirateChoices: {
...prevState.PirateChoices,
SelectedShip: value
}
}), () => {console.log(this.state)}
);
}
}
I have a generic component that loads a select form that takes the change function and triggers onchange.
So the first thing the app does is get Years and PirateCaptains from a service and sets the state of those (as well as the Selected Ship and PirateCaptain which is the first entry of the array shown). On change the selected is updated.
The problem I have is that the Ship data depends on the combination of SelectedPirateCaptain and SelectedYear.
I feel like the easy way of populating that is having it trigger on change of either of those two properties, but I can't figure out a way to set up a function to do that.
I've also tried (for initial loads) using promises or callbacks but can't seem to figure out how to get it to wait until the state of both selected properties has a value. (I tried a while loop but the function never seems to get the state with the value.)
Any help is greatly appreciated in advance, I suspect I'm being an idiot and missing something obvious so thanks in advance.

Put request on Material UI switch

I am building out a switch which reads it's checked value from the value I retrieve from the backend, and when a user toggles it, a PUT request is sent to backend to update the choice.
This is what I have so far, the toggle isn't displaying the response, what am I missing here
class Test extends Component {
constructor(props) {
super(props);
this.state = {
toggleValue: ''
}
}
componentDidMount() {
this.props.getToggleValue();
}
toggleValue = () => {
if(this.props.value){
return this.props.value.toggleValue
}
}
handleChange(field) {
return (event) => {
this.setState({
[field]: event.target.value,
});
}
}
render() {
return (
<>
<Switch value={this.state.toggleValue} checked={this.toggleValue()} onChange={this.handleChange('toggleValue')} />
</>
)
}
const mapStateToProps = (state, ownProps) => {
return {
...ownProps,
value: state.testReducer.value
};
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
getToggleValue
}, dispatch);
};
You have to check for event.target.checked and not event.target.value
handleChange(field) {
return (event) => {
this.setState({
[field]: event.target.checked,
});
}
}

No unused expressions on function inside componentDidMount

How can I fix or disable ESLint to ignore
[eslint] Expected an assignment or function call and instead saw an expression. (no-unused-expressions)
on this
authUser
? this.setState(() => ({ authUser }))
: this.setState(() => ({ authUser: null }));
Whilst, I understand the reason for the error and could just ignore it - as it's doing everything that it's is intended for.
Is there a way to remove this error from this document only, not globally? Or perhaps, is there a better way for me to rewrite this to avoid the error whilst achieving the same outcome?
Full Component
const withAuthentication = Component =>
class WithAuthentication extends React.Component {
constructor(props) {
super(props);
this.state = {
authUser: null
};
}
componentDidMount() {
firebase.auth.onAuthStateChanged(authUser => {
authUser
? this.setState(() => ({ authUser }))
: this.setState(() => ({ authUser: null }));
});
}
render() {
const { authUser } = this.state;
return (
<AuthUserContext.Provider value={authUser}>
<Component {...this.props} />
</AuthUserContext.Provider>
);
}
};
export default withAuthentication;
How about trying if then else?
firebase.auth.onAuthStateChanged(authUser => {
if (authUser)
this.setState(() => ({ authUser }))
else
this.setState(() => ({ authUser: null }));
});

Categories

Resources