Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace of setState callback in react hook with useEffect hooks for complicated scenario not working

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.

like image 492
user12893845 Avatar asked Feb 13 '20 17:02

user12893845


Video Answer


1 Answers

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.

like image 96
arjun sah Avatar answered Sep 25 '22 05:09

arjun sah