Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Current »

Walkthrough and React Fundamentals:

Initialize app

In src/index.jsx

comment out lines 17-34, and replace with:
ReactDOM.render(<div>Hello World</div>, document.getElementById('root'));

Fetch data from a variety of devstack apis

Display data in generic JSX

Generate custom display of devstack API data with Paragon components

Send messages to devstack API and update on response

Topics to review:

  • How does a react app “initialize”? What is different about MFE initialization? Why?

  • Brief understanding of tools:

    • Webpack

    • Babel

    • Eslint

    • Jest

  • Helpful simple ES6 syntax

  • React components

    • What makes a component?

    • How to define PropTypes?

    • What makes a component update (component lifecycle)?

    • Behavior vs render

    • Basic hooks for render (useState, useEffect)

    • Generic custom hook extraction

    • How to test generic react behavior

  • Network interaction

    • What are Promises? How do they work? How do we work with them?

    • How do we make asynchronous network requests?

    • Where should network requests be defined in the project?

    • How do we load data in from network api sources?

Example Output

import React from 'react';

import { useKeyedState } from '@edx/react-unit-test-utils';
import { Container } from '@edx/paragon';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform/config';


const apis = {
  courses: 'courses/v1/courses/',
  mfe_context: 'mfe_context',
};

const { courses } = apis;

const courseAPIs = {
  // blocks: (course_id) => `courses/v2/blocks/?course_id=${course_id}`,
  instructorReports: (course_id) => `instructor/v1/reports/${course_id}`,
  instructorTaskScheduledBulkEmails: (course_id) =>
    `instructor_task/v1/schedules/${course_id}/bulk_email/`,
};

const useExamplePageData = () => {
  const get = (uri) => getAuthenticatedHttpClient()
    .get(`${getConfig().LMS_BASE_URL}/api/${uri}`);
  const [apiObjects, setAPIObjects] = useKeyedState('apiObjects', {});
  const [courseAPIObjects, setCourseAPIObjects] = useKeyedState('courseAPIObjects', {});
  const logAPI = (key, uri) => {
    get(uri).then(({ data }) => {
      apiObjects[key] = data;
    });
  };
  React.useEffect(() => {
    Object.keys(apis).forEach(key => {
      get(apis[key]).then(({ data }) => {
        setAPIObjects({ ...apiObjects, [key]: data });
        setAPIObjects((old) => ({ ...old, [key]: data }));
      });
    });
    get('courses/v1/courses/').then(({ data }) => {
      const { course_id } = data.results[0];
      Object.keys(courseAPIs).forEach(key => {
        get(courseAPIs[key](course_id)).then(({ data }) => {
          setCourseAPIObjects((old) => ({ ...old, [key]: data }));
        });
      });
    });
  }, []); // empty list means only on first load.
  
  
  /*
  // called EVERY render
  React.useEffect(() => { doThingAllTheTimes(); });
  // called when myVal changes.
  React.useEffect(() => { doThingWhenMyValChanges(myVal); }, [myVal]);
  // called when EITHER myVal or val2 change.
  React.useEffect(() => { doThingWhenMyValsChanges(myVal, val2); }, [myVal, val2]);
  */
  // ^ Runs risk of inifinite loop, so safeguards generally added.
  return { apiObjects, courseAPIObjects };
};

const ExamplePage = () => {
  const { apiObjects, courseAPIObjects } = useExamplePageData();
  return (
    <main>
      <Container className="py-5">
        <h1>Example Page</h1>
        <p>Hello world!</p>
        <br />
        <b>API Objects</b>
        {Object.keys(apiObjects).map((key) => (
          <pre>{JSON.stringify(apiObjects[key], null, 2)}</pre>
        ))}
        <br />
        <b>Course API Objects</b>
        {Object.keys(apiObjects).map((key) => (
          <pre>{JSON.stringify(apiObjects[key], null, 2)}</pre>
        ))}
      </Container>
    </main>
  );
};

export default ExamplePage;

  • No labels