OiO.lk Blog javascript How to async await in react render function?
javascript

How to async await in react render function?


I need to display JSX that depends on data from a network request. In my first attempt, the return statement was hit before the network request resolved

const showSubscriptions = () => {
  const [methods, setMethods] = useState([]);
  let subscriptionsRef = React.useRef({})

  useEffect(() => {
    const getCommunicatorMethods = async () => {
      const { data } = await axios.get(
        "/api/get_communicator_methods",
      );

      const routingKeys = await axios.get("api/get_routing_keys")
      let routingKeysString = JSON.stringify(routingKeys.data)
      let detections = routingKeysString.includes('Detection')
      let zones = routingKeysString.includes('Zone')
      let sensors = routingKeysString.includes('Sensor')
      let notifications = routingKeysString.includes('Notification')
      let system_configurations = routingKeysString.includes('SystemConfiguration')
      let alerts = routingKeysString.includes('Alert')

      subscriptionsRef.current = { 'subscribe_to_sensors': sensors, 'subscribe_to_zones': zones, 'subscribe_to_alerts': alerts, 'subscribe_to_notifications': notifications, 'subscribe_to_detections': detections, 'subuscribe_to_system_configurations': system_configurations }

      console.log(subscriptionsRef.current)
      setMethods([...Object.values(data)]);
    };

    console.log(subscriptionsRef.current) //[methods[0][0]]
    getCommunicatorMethods();
  }, []);

  return methods
    .filter((x) => x[0].includes("subscribe"))
    .map((method) => (
      <div key={method[0]}>
        <span>{method[0].replaceAll("_", " ")}</span>
        <Switch value={subscriptionsRef.current[method[0]]} onChange={handleChange(method[0])} />
      </div>
    ));
};

Then I tried making the fn async so I can wait on the network request (I also had to get rid of the useEffect() so that await is at the top-level within the async function):

const showSubscriptions = () => {
  const [methods, setMethods] = useState([]);
  let subscriptionsRef = React.useRef({})

  const getCommunicatorMethods = async () => {
    const { data } = await axios.get(
      "/api/get_communicator_methods",
    );

    const routingKeys = await axios.get("api/get_routing_keys")
    let routingKeysString = JSON.stringify(routingKeys.data)
    let detections = routingKeysString.includes('Detection')
    let zones = routingKeysString.includes('Zone')
    let sensors = routingKeysString.includes('Sensor')
    let notifications = routingKeysString.includes('Notification')
    let system_configurations = routingKeysString.includes('SystemConfiguration')
    let alerts = routingKeysString.includes('Alert')

    subscriptionsRef.current = { 'subscribe_to_sensors': sensors, 'subscribe_to_zones': zones, 'subscribe_to_alerts': alerts, 'subscribe_to_notifications': notifications, 'subscribe_to_detections': detections, 'subuscribe_to_system_configurations': system_configurations }

    setMethods([...Object.values(data)]);
  };

  console.log(subscriptionsRef.current) //[methods[0][0]]
  getCommunicatorMethods();

  return methods
    .filter((x) => x[0].includes("subscribe"))
    .map((method) => (
      <div key={method[0]}>
        {/* {subscriptionsRef.current[method[0]]} */}
        <span>{method[0].replaceAll("_", " ")}</span>
        <Switch value={subscriptionsRef.current[method[0]]} onChange={handleChange(method[0])} />
      </div>
    ));
};

The problem is that when I do this, I get the following error (as it seems React doesn’t allow returning JSX from an async component)

Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.



You need to sign in to view this answers

Exit mobile version