Hi I have a scenario where i need to replace setState callback after setting new state in react hooks with React_hooks in a particular scenario.
The current code is::
const ThemeOptions = () => {
const [previewType, setPreviewType] = useState("Desktop");
const [previewUrl, setPreviewUrl] = useState("");
const [layout, setLayout] = useState(null);
const [saving, setSaving] = useState(false);
const handleSave = (newdata) => {
setLayout(newdata);
setSaving(true);
axios
.put(window.urls.save, this.state.layout)
.then(
function(response) { // i want this to change in hooks
this.setState(
{
layout: response.data,
saving: false,
},
function() {
this.refs["preview"].refresh();
}
);
}.bind(this)
)
.catch(
function(error) {
console.log(error);
setSaving(false);
}.bind(this)
);
}
return (
<div>
<Router>
<div className="theme_options">
<div className="row" style={{ height: 100 + "vh" }}>
<Sidebar
layout={layout}
onSave={handleSave}
onReset={this.handleReset}
previewType={previewType}
onChangeScreen={handlePreviewScreenChange}
saving={saving}
/>
<div className="col main">
<span className="d-none d-md-block">
<Preview
ref="preview"
type={this.state.previewType}
url={this.state.previewUrl}
/>
</span>
</div>
</div>
</div>
</Router>
</div>
)
}
I want the success callback function of axios.put requests to be changed in hooks as in the above code there is usage of setState along with callback in it.
The major code to refactor is::
this.setState(
{
layout: response.data,
saving: false,
},
function() {
this.refs["preview"].refresh();
}
);
I was thinking of doing ::
useEffect(()=> {
// i dont know what to put there...
),[]);
I want the callback in setState() to happen in react hooks. Kindly suggest me an ideal way to do this considering the above code.
so this is a very simple yet difficult puzzle which many person find it hard to tackle. Use the below code and it will for sure run and execute its task perfectly:: in the state add one additional flag of 'isError' :
const [layout, setLayout] = useState(null);
const [saving, setSaving] = useState(false);
const [iserror, setIserror] = useState(true);
and use a useEffect like below. The first time useeffect will run but since the condions in useeffect is of specific type it will not run the IF block at all.and IF block will run only on specific conditions mentioned below. But mind it that useEffect will run everytime any of the dependency array elements change but the IF block will not execute at all.
useEffect(()=>{
if(layout && !saving && !iserror){
console.log('specific case render ');
this.refs["preview"].refresh();
}
},[layout,saving,iserror]);
had we put the default conditions of states in IF block then only IF block inside effect would run which is not the case as mentioned above. As we want the setState callback to run only after some specific condition and not always. If we change the above code to something like this then::
//for understanding purpose only default states
layout==null,
saving == false
isError== true
//
useEffect(()=>{
if(layout == null && !saving && iserror){ //observe this default case
console.log('default case render ');
}
},[layout,saving,iserror]);
The handleSave function will do its task with little change::
const handleSave = (newdata) => {
setLayout(newdata); // useEffect run as layout changed but conditions
// not satisfied
setSaving(true); // useEffect will run since saving changed
// not satisfied
axios
.put(window.urls.save, layout)
.then(
function(response) { // only this case forces the code in
// useEffect to run as 3 below cases are
// satisfied
setLayout(response.data);
setSaving(false);
setIserror(false);
}.bind(this)
)
.catch(
function(error) {
console.log(error);
setSaving(false);// only 2 case satisfied i.e layout before
// axios line and saving but not iserror.
setIserror(true);
}.bind(this)
);
}
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With