2

I started to change the codes from class based to function based. (Sorry if im wrong to say that. I mean i am just deleting "this" , "render" keywords, so it becomes function based as I know.

Here is the first part which i changed :

const GlobalContext = createContext({});

const GlobalContextProvider = () => {
  const [JSON, setJSON] = useState('.json?cache=2');
  const [debug, setDebug] = useState(true);
  const [currentTheme, setCurrentTheme] = useState("light");
  const [keyboardOpen, setKeyboardOpen] = useState(false);
  const [isBottomSheetOpen, setBottomSheetOpen] = useState(false);
  const [showSplash, setShowSplash] = useState(true);
  const [showLoginRegister, setShowLoginRegister] = useState(true);
  const [inAction, setInAction] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [isUploading, setIsUploading] = useState(false);
  const [userToken, setUserToken] = useState({
    email: "",
    password: ""
  });
  const [userData, setUserData] = useState({
    name:"",
    surname:"",
    email:"",
    accountType:"",
    remaining:0,
    quota:0,
    corporate:"",
    apiKEY:"",
    apiURL:""
  });
  const [folderData, setFolderData] = useState([]);
  const [receiptData, setReceiptData] = useState([]);
  const [currentData, setCurrentData] = useState([]);
  const [baseEmptyData, setBaseEmptyData] = useState([]);
  const [extra, setExtra] = useState([]);
  const [items, setItems] = useState([{
    urunAdi: '',
    tutar: '',
    kdv: ''
    }
  ]);
  const [toastRef, setToastRef] = useState({});
  const [sheetRef, setSheetRef] = useState(null); // its same as doing useState({})
  const [settings, setSettings] = useState({
    theme: 'light',
    maxYear: 2,
    showEmpty: false,
  });

  // componentDidMount and componentWillMount Parts here
  const KeyboardFunction = () => {
    useEffect(() =>  {
      Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
      Keyboard.addListener("keyboardDidHide", _keyboardDidHide);

      // cleanup function
      return () => {
        Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
        Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
      };
    }, []);
  }
  
  _keyboardDidShow = () => setKeyboardOpen(true);
  _keyboardDidHide = () => {
    return (
      setTimeout(() => {
        setKeyboardOpen(true)
      }, 200) // 200 ms
    );
  }

  const setBottomSheet = (val) => setBottomSheetOpen(val);

  /* MISC BEGIN */
  const log = (...args) => {Debug ? console.log(Array.prototype.slice.call(args).join(" ")): undefined};

And for callback in useEffect(), I defined this. How can I call setCB() in useEffect() function?

const [cbRef,setCB] =  useState();  // this is for calling callback functions in useEffect()
  useEffect(()=> {
    if(cbRef != null){
      cbRef();
    }
  },[cbRef]);

How can I change the rest? The rest is like that, I mean if you could help me with one function, I may do the same with other functions, they look similar.

 loadSettings = async (callback) => {
    try {
      const data = await AsyncStorage.getItem('settings');
      if (data !== null) {
        const jData = Object.assign({}, this.state.settings, JSON.parse(data));
        this.setState({ settings: jData, currentTheme: jData.theme }, () => {
          callback();
        });
      } else {
        await AsyncStorage.setItem('settings', JSON.stringify(this.state.settings));
        this.setState({ currentTheme: 'light' }, () => {
          callback();
        });
      }
    } catch (err) {
      this.Log('loadSettings Error => ', err);
      callback();
    }
  }
  saveSettings = async (key, value, callback) => {
    try {
      let jData = this.state.settings;
      jData[key] = value;
      this.Log(jData);
      await AsyncStorage.setItem('settings', JSON.stringify(jData));
      this.setState({ settings: jData }, () => {
        if (callback != undefined) {
          callback();
        }
      })
    } catch (err) {
      this.Log('saveSettings Error => ', err);
      if (callback != undefined) {
        callback();
      }
    }
  }
  toggleTheme = (callback) => {
    this.setState(({ currentTheme }) => ({
      currentTheme: currentTheme === 'light' ? 'dark' : 'light',
    }), () => {
      callback();
    });
  };
  /* MISC END */

  /**
   * Save data to currentData state in order to reach from different scenes.
   * Params: currentData:string, callback:function -> void
   */
  setCurrentData = (currentData, callback) => {
    this.setState({ currentData }, () => {
      if (callback != undefined) { callback(); }
    });
  }

  /**
   * Hide Splash Screen
   * Params: NONE
   */
  hideSplash = () => { this.setState({ showSplash: false }); };

  /**
   * Hide Login-Register Screen
   * Params: NONE
   */
  hideLoginRegister = () => { this.setState({ showLoginRegister: false }); };

  /**
   * Get Async Storage Data from Device, such as userToken or App Settings
   * Params: DataKey:string, callback:function -> json
   */
  getDataFromPhone = async (dataKey, callback) => {
    try {
      const data = await AsyncStorage.getItem(dataKey);
      if (data !== null) {
        callback({ "errorCode": -1, "data": JSON.parse(data) });
      } else {
        this.Log('Data ("' + dataKey + '") you try to fetch is empty');
        callback({ "errorCode": "ASYNC_STORAGE_EMPTY" });
      }
    } catch (err) {
      this.Log('getDataFromPhone Error => ', err);
      callback({ "errorCode": "ASYNC_STORAGE_EMPTY" });
    }
  }

  /**
   * Set Async Storage Data on Device, such as usertoken or App Settings
   * Params: DataKey:string, Data:string, callback:function -> json
   */
  setDataToPhone = async (dataKey, data, callback) => {
    try {
      await AsyncStorage.setItem(dataKey, JSON.stringify(data));
      if (callback != null || callback != undefined) {
        callback({ "errorCode": -1 });
      }
    } catch (err) {
      this.Log('setDataToPhone Error => ', err);
      if (callback != null || callback != undefined) {
        callback({ "errorCode": "ASYNC_STORAGE_SETITEM" });
      }
    }
  }

  /* FILE ACTION BEGIN */

  /**
   * Set Uploading State to given param
   * Params: Uploading:boolean, callback:function -> void
   */
  setUploading = (uploading, callback) => {
    this.setState({ uploading }, () => {
      if (callback != undefined) {
        callback();
      }
    });
  }

5 Answers5

0

As request, this is an example for one of your functions.

Since you have declared const [ settings, setSettings ] = useState(), you may use settings directly instead of this.state.settings

useState does not accept a callback, so you need to move the call back into useEffect.

 loadSettings = async (callback) => {
    try {
      const data = await AsyncStorage.getItem('settings');
      if (data !== null) {
        const jData = Object.assign({}, settings, JSON.parse(data));
        setSettings({ settings: jData, currentTheme: jData.theme })
      } else {
        await AsyncStorage.setItem('settings', JSON.stringify(settings));
        setSettings({ currentTheme: 'light' });
      }
    } catch (err) {
      this.Log('loadSettings Error => ', err);
      callback(); 
    }
  }

useEffect(() => {
     callback() //the callback function
},[settings])

With the dependency [settings] in useEffect, it will be called whenever the settings state is changed.

You can have multiple useEffect in each functional component.

Bonus

If you only want to call useEffect once when page loads, you leave the dependency empty like following.

useEffect(() => {
   //whatever function i want to call when component mounts.
}, [])
Someone Special
  • 12,479
  • 7
  • 45
  • 76
  • Thank you so much for replying. I am just trying to learn react-native. I am asked to change all the project into function based at company,(i am intern trying to get job offer, if they like me they will offer) Well, do i have to understand all the codes in the project, or i just should adapt the codes into function based, and its okay? Btw should i write `[settings]` or `[settings,currentTheme]`since it will do callback based on currentTheme? –  Apr 29 '21 at 05:47
  • 1
    you add `currentTheme`. Don't worry about things as when you miss out on any dependency, e.g. `currentTheme`, there will be a warning. – Someone Special Apr 29 '21 at 06:17
  • Thank you. By the way does async() not get any props, since its just a keyword for declaring a function asynchronous. So I should only write `async()` then ? –  Apr 29 '21 at 06:43
  • 1
    using `async` makes the function an asynchronous function, and is necessary if you want to use `await` inside the function. It accepts empty props, you are correct. – Someone Special Apr 29 '21 at 06:49
  • Btw `callback` is a function what we call from `async(callback)`, so in `useEffect()` it will return me undefined. How can I call it in `useEffect()`? I defined something like this `const [cbRef,setCB] = useState(); // this is for calling callback functions in useEffect() useEffect(()=> { if(cbRef != null){ cbRef(); } },[cbRef]); ` but i dont know how to call it in useEffect. –  Apr 29 '21 at 08:51
0

The useState hook doesn't have a callback to call after state has been updated, you should use an useEffect hook with a dependency on the state that was updated.

this.Log should now also be your log function, and the miscellaneous references to this.state.XXX should just be the new state variables you defined previously via useState hooks.

loadSettings = async (callback) => {
  try {
    const data = await AsyncStorage.getItem('settings');
    if (data !== null) {
      const jData = Object.assign({}, settings, JSON.parse(data));
      setSettings(jData);
      setCurrentTheme(jData.theme);
    } else {
      await AsyncStorage.setItem('settings', JSON.stringify(settings));
      setCurrentTheme('light');
    }
  } catch (err) {
    log('loadSettings Error => ', err);
    callback();
  }
}

useEffect(() => { // <-- hook callback called when any dependency updates
  callback();
}, [settings, currentTheme]); // <-- add any other dependencies to array
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Thank you so much for answering. So we will write `[settings, currentTheme]`, is it because it will callback based on currentTheme? or it would still work if i only write `[settings]` for that part? –  Apr 29 '21 at 05:48
  • Also should I add callback inside async, like `async(callback)` ? –  Apr 29 '21 at 05:50
  • 1
    @user15775693 You should add all the values to the dependency array that you want to trigger calling `callback`. No, `async` isn't a function you call, it's a keyword to declare a function asynchronous and allows you to `await` values within *that* function's scope. – Drew Reese Apr 29 '21 at 05:53
  • 1
    I understand now. So other friend which did this project in class based did this wrong then. Thank you again. Btw I want to ask you something. Well I am an intern at a company. They will job offer me only if they think i am helpful and if they see a potential in me. This is my task, changing codes to function based. Then I will be only one person who is responsible with this react-native project. How can I improve my knowledge? I want to get this job. Thanks –  Apr 29 '21 at 06:02
  • 1
    @user15775693 Mostly same answer as previously, just lots of reading official documentation and practice (codesandbox is great for JS/react, and Expo snacks for react-native) creating little demos for concepts you read about. I started trying to answer questions here on SO and gradually got better at quickly reading other people's code and assessing what the issue is and finding solutions. Gradually you start seeing common patterns where mistakes and issues occur. – Drew Reese Apr 29 '21 at 06:06
  • Okay Sir, thank you a lot. You helped me so much. I'll pray for you to have always great, happy, succesful, healthy life :) –  Apr 29 '21 at 06:14
  • 1
    @user15775693 Welcome. If you've found answers helpful then you can also show your appreciation by upvoting them. Again, cheers and good luck. – Drew Reese Apr 29 '21 at 06:17
  • Of course, I upvoted. Thanks, good luck to you too. When I have questions, I may bother you :) –  Apr 29 '21 at 06:40
  • Could you look at `saveSettings = async (key, value, callback) => {}` in the question. I mean since key and value is being used in the function, i should write it like `async(key,value)` only deleting callback? since you said i shouldnt add callback there previously. –  Apr 29 '21 at 07:14
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231723/discussion-between-drew-reese-and-user15775693). – Drew Reese Apr 29 '21 at 07:19
  • Sir, could you look at my edit on the question? I defined a function, to call it in `useEffect()`. But dont know how to reach it in `useEffect()` . Shouldnt it be something like `setCB(callback)` –  Apr 29 '21 at 09:00
  • should i only write setCB(callback) in loadSettings() function, ? so it will do useEffect() already. –  Apr 29 '21 at 09:04
0

when declaring states with hooks like useState and useEffect, you don't need to bind the functions. For example, you declared a state like

const [settings, setSettings] = useState({
    theme: 'light',
    maxYear: 2,
    showEmpty: false,
  });

so, you can refer to it without using this.state , and one more thing is useState cannot accept callback, but useEffect can because it uses lifecycles methods of react.

Summary:

instead of using this.state.name , use directly name and where there are callbacks, use useEffect.

Aqib Naeem
  • 431
  • 3
  • 11
  • 1
    Thank you for your answer. Could I ask how to improve my knowledge, just learning react-native. Watching videos becomes boring after some time. Do you think I could learn by changing these project codes to functional base? –  Apr 29 '21 at 05:57
  • 1
    i read official react documentation, and second, i read people's posts and code in the discord server which helps me soo much to see same things with a different perspective. https://discord.gg/bQ6Auyav – Aqib Naeem Apr 29 '21 at 06:05
  • Thank you. I see I should study so hard. :) –  Apr 29 '21 at 06:15
  • Could you look at my edit on the question? There is "callback" function which comes inside `async(callback)` , i try to get it in `useEffect()`, so i defined a function, and try to call it in other functions like loadSettings, saveSettings etc. How can i do that? –  Apr 29 '21 at 09:29
  • 1
    I have answered overthere. Do let me know, if it helps you or not – Aqib Naeem Apr 29 '21 at 14:31
  • 1
    Of course it helped. But isnt this a bit different in my question that i sent link –  Apr 29 '21 at 14:35
  • 1
    Ohh sorry, I did not notice too much, but now you have edited the question and delete the logout function code snippet from your post. – Aqib Naeem Apr 29 '21 at 14:41
  • 1
    Yeah because you told me the right way for it. Thank you for it. Now i am trying to understand the other part of the question... I have a given project that has codes like this, im expected to change it to functional based from class based. But i cant do, i dont understand well enough... idk what to do. –  Apr 29 '21 at 14:46
  • 1
    don't be soo hard on yourself, keep searching for the solutions and you will start grapping concepts, great things take time. – Aqib Naeem Apr 29 '21 at 14:50
  • 1
    thank you for the courage... I am an intern at a company tho, if they like me they will offer me job, but i couldnt do anything almost in 1.5 months...I try to understand, but i feel i dont learn anything, I know some people who were not succesful or hardworking, but they got into this field and work for years, but i am having hard time to learn things.:( –  Apr 29 '21 at 14:53
  • 1
    I have seen, it's been 3 days since you joined this amazing community, so, take benefit from there, Converting whole code into something new is never easy. Best of Luck. Just dont give up!!!! Happy Coding!!. – Aqib Naeem Apr 29 '21 at 15:06
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231749/discussion-between-aqib-naeem-and-user15775693). – Aqib Naeem Apr 29 '21 at 15:07
0

I am answering your another question which you asked me in comment.. So, after doing a little research, i have come across a solution. Let take an example of

     function example({ userId }) {
      const [data, dataSet] = useState();
    
  // this external asynchronous function is called in useEffect
      const fetchMyAPI = useCallback(async () => {
        let response = await fetch('api/data/' + userId)
        response = await response.json()
        dataSet(response)
      }, [userId])
                
    
      useEffect(() => {
        fetchMyAPI()
      }, [fetchMyAPI])
    
    }

Notice the difference.. try using

const loadSettings = useCallback(async () => {
    //code here
})

instead of

loadSettings = async (callback) => {
     //code here
}

if you want more help then must consider reading that post

Aqib Naeem
  • 431
  • 3
  • 11
  • 1
    Thank you for taking time to answer. Can I ask you another question which i have problem with, –  Apr 29 '21 at 13:14
  • 1
    yeah sure. I will try my level best to answer it. – Aqib Naeem Apr 29 '21 at 13:22
  • thank you friend.. I was going to ask here, but it would be complex thing because id have to add the first part of codes, and then there is no enough space here... Thanks anyway. I tried to open chat on here, it would be easier to ask you but i couldnt open chat –  Apr 29 '21 at 13:46
  • Btw how can i change this, by deleting "this " keywords, `const logout = () => { this.setToken({ email: '', password: '', }, () => { this.setState({ showLoginRegister: true }) }); } `since i wont use class –  Apr 29 '21 at 13:51
  • 1
    sorry, but I am not familiar with react-native. your question seems a little higher than my knowledge too. – Aqib Naeem May 01 '21 at 09:22
  • 1
    its ok, thank you for the reply anyway :) –  May 01 '21 at 10:10
0

As you have already declared state in your program using hooks like:

const [showLoginRegister, setShowLoginRegister] = useState(true);
 const [userToken, setUserToken] = useState({
    email: "",
    password: ""
  });

so, you don't need to use "this" keyword in order to use or set state of functional component.

const logout = () => { 
  setToken({ 
      email: '', password: '', 
   }, () => { 
       showLoginRegister: true
  }); 
}

Now look what I have done is just erase "this" keyword from your syntax.

NOTE

if you are confused with the "this" statement, then remember, that "this" keyword is only used to call/refer react state in class components. In functional components, you can call/refer to the state directly. But there are more valid reasons behind that.

Aqib Naeem
  • 431
  • 3
  • 11
  • Thanks so much. I was just confused when i saw showLoginRegister inside another state thats setToken and it has two properties.. Now I understand –  Apr 29 '21 at 14:32