-2

I am developing a website in which I want to be able to access the state information anywhere in the app. I have tried several ways of implementing state but I always get following error message:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of SOS.

Here is my SOS->index.js file:

import React, { useContext } from 'react';
import axios from 'axios';
import CONST from '../utils/Constants';
import { Grid, Box, Container } from '@material-ui/core';
import { styled } from '@material-ui/styles';
import { Header } from '../Layout';
import ListItem from './ListItem';
import SOSButton from './SOSButton';
import FormPersonType from './FormPersonType';
import FormEmergencyType from './FormEmergencyType';
import StateContext from '../App';
import Context from '../Context';

export default function SOS() {
  const { componentType, setComponentType } = useContext(Context);
  const timerOn = false;
  //'type_of_person',
  const ambulance = false;
  const fire_service = false;
  const police = false;
  const car_service = false;

  //static contextType = StateContext;
  const showSettings = event => {
    event.preventDefault();
  };

  const handleComponentType = e => {
    console.log(e);
    //this.setState({ componentType: 'type_of_emergency' });
    setComponentType('type_of_emergency');
  };

  const handleEmergencyType = new_emergency_state => {
    console.log(new_emergency_state);
    //   this.setState(new_emergency_state);
  };

  const onSubmit = e => {
    console.log('in OnSubmit');
    axios
      .post(CONST.URL + 'emergency/create', {
        id: 1,
        data: this.state //TODO
      })
      .then(res => {
        console.log(res);
        console.log(res.data);
      })
      .catch(err => {
        console.log(err);
      });
  };

  let component;

  if (componentType == 'type_of_person') {
    component = (
      <FormPersonType handleComponentType={this.handleComponentType} />
    );
  } else if (componentType == 'type_of_emergency') {
    component = (
      <FormEmergencyType
        handleComponentType={this.handleComponentType}
        handleEmergencyType={this.handleEmergencyType}
        emergencyTypes={this.state}
        timerStart={this.timerStart}
        onSubmit={this.onSubmit}
      />
    );
  }
  return (
    <React.Fragment>
      <Header title="Send out SOS" />
      <StateContext.Provider value="type_of_person" />
      <Container component="main" maxWidth="sm">
        {component}
      </Container>
      {/*component = (
        <HorizontalNonLinearStepWithError
          handleComponentType={this.handleComponentType}
        />*/}
    </React.Fragment>
  );
}

I would really appreciate your help!

Just for reference, the Context file is defined as follows:

import React, { useState } from 'react';

export const Context = React.createContext();

const ContextProvider = props => {
  const [componentType, setComponentType] = useState('');
  setComponentType = 'type_of_person';
  //const [storedNumber, setStoredNumber] = useState('');
  //const [functionType, setFunctionType] = useState('');
  return (
    <Context.Provider
      value={{
        componentType,
        setComponentType
      }}
    >
      {props.children}
    </Context.Provider>
  );
};

export default ContextProvider;

EDIT: I have changed my code according to your suggestions (updated above). But now I get following error: TypeError: Cannot read property 'componentType' of undefined

  • You can't change the value of `affected` by this way. You need to use the function returned by the second position by `useState`: `const [affected, setAffected] = useState(''); setAffected('type_of_person');` – macabeus Jun 23 '19 at 13:20
  • 1
    What do you mean *"if I uncomment the render function"*? You're writing a functional component, not a class-based one; it doesn't have a `render` method. – jonrsharpe Jun 23 '19 at 13:20
  • You need to read up on functional and class components! https://reactjs.org/docs/components-and-props.html#functional-and-class-components – Einar Ólafsson Jun 23 '19 at 13:21
  • Also, `useContext(Context)` will return an object, so you can't do this `if`: `componentType == 'type_of_person'`. You could access it using `const { affected: componentType } = useContext(Context)` – macabeus Jun 23 '19 at 13:23
  • @Macabeus thank you, could you help me with the new error which you can see in the edit of the question? – pythonlearner Jun 23 '19 at 13:44

1 Answers1

0

Context is not the default export from your ../Context file so you have to import it as:

import { Context } from '../Context';

Otherwise, it's trying to import your Context.Provider component.

For your file structure/naming, the proper usage is:

// Main app file (for example)
// Wraps your application in the context provider so you can access it anywhere in MyApp
import ContextProvider from '../Context'

export default () => {
  return (
    <ContextProvider>
      <MyApp />
    </ContextProvider>
  )
}
// File where you want to use the context
import React, { useContext } from 'react'
import { Context } from '../Context'

export default () => {
  const myCtx = useContext(Context)

  return (
    <div>
      Got this value - { myCtx.someValue } - from context
    </div>
  )
}

And for godsakes...rename your Context file, provider, and everything in there to something more explicit. I got confused even writing this.

I'm Joe Too
  • 3,490
  • 1
  • 12
  • 20
  • Thank you! And how can I modify the context attributes in other files apart from the main app file? – pythonlearner Jun 23 '19 at 14:28
  • Call your setComponentType function that is passed down through your context. Your context (the way you set it up) is an object. So when you call `const myCtx=useContext(Context)`, you'll have access to `myCtx.componentType` and `myCtx.setComponentType()`. If it's broken right now, it's because you have `setComponentType = 'type_of_person';` in your Context file. Remove that and set your initial context with `const [componentType, setComponentType] = useState('type_of_person')` – I'm Joe Too Jun 23 '19 at 14:46