1

Background

I created a fully functional component. The component has state and props, and there are many methods inside. My component should work differently according to the os(ios / android). So I solved this problem by if statement like below.

if( platform.os == 'ios') { ... } else { ... }

The problem was that as the code volume increased, there was a problem with readability, and I decided to make a separate component for IOS and for Android. The first thing that came to mind was inheritance because ES6 and Typescript Support Class. The picture of concept is this.

enter image description here

However, React does not recommend inheritance. So I was just going to hand over the functions overridden by props to the Speech component in the SpeechIOS component's render function.

The code is as follows.

Speech.tsx

type Props = {
  team: number,
  onSpeechResults: (result: string) => void
  ...
}
type States = {
  active: boolean;
  error: string;
  result: string;
  ...
};

export default class Speech extends Component<Props,States> {
  state = { ... };
  constructor(props: Props) {
    super(props);
    ...
  }

  // render
  render() {
    ...
    return (
      <ImageBackground source={require("../images/default-background.jpeg")} style={styles.full}>
        ...
      </ImageBackground>
    );
  }
  sendCommand = (code: number, speed: number, callback?: () => void) => { ... }
  getMatchedSpell = (spellWord: string): { code: number, speed: number } => { ... }
  onSpeechResults(e: Voice.Results) { ... };
  ...
}

SpeechIOS.tsx

import Speech from './Speech';

type Props = {}
type States = {}
export default class SpeechIOS extends Component<Props,States> {
  constructor(props: Props) {
    super(props);
    ...
  }

  // render
  render() {
    ...
    return ( <Speech team="1" onSpeechResults={this.onSpeechResults}></Speech> );
  }

  sayHello() {
    console.log("Hello!!");
  }

  // I want that Speech Component call this onSpeechResults function
  onSpeechResults(result: string) {
    this.setState({...});
    let temp = this.getMatchedSpell( ... ); // which is in Speech Component
    this.sendCommand( 10, 100 ... ); // which is in Speech Component
    this.sayHello(); // which is in SpeechIOS component only
    ... other things..
  };
}

Problem.

As you can see, the onSpeechResults which is in SpeechIOS Component use some functions in Speech Component and in SpeechIOS Component also.

So, How to solve this problem? Should I use Inheritance?

Byeongin Yoon
  • 3,233
  • 6
  • 26
  • 44

3 Answers3

1

You should define a top level component that defines the shared props and methods, and use those to render either your ios or android component. pass the props and methods to the children. This is composition which is favored over inheritance in react. example:

class Speech extends React.Component {

  state ={shared: 'state'}

  sharedMethod = () => {
    this.setState({blah: 'blah})
  }

  render() {
    const Root = Platform.select({
      ios: SpeechIOS,
      android: SpeechAndroid
    })

    return <Root onClick={this.sharedMethod}  shared={this.state.shared}/>
  }

}
chris
  • 6,653
  • 6
  • 41
  • 54
  • But How to call a function which is in SpeechIOS in Speech Component ? – Byeongin Yoon Nov 22 '19 at 04:34
  • And should I pass all shared method and state as props to SpeechIOS ??.. I think my code would be too long and complicated. – Byeongin Yoon Nov 22 '19 at 04:35
  • pass only what you need. use object spread if necessary . alternatively investigate the docs on using React Context. If you find yourself needing to call a child method from a parent, you are venturing into imperative land and should re-evaluate your dependency direction. https://stackoverflow.com/questions/37949981/call-child-method-from-parent – chris Nov 22 '19 at 04:41
1

Alternatively, break out any common logic into a utility function like SpeechUtil.ts, a whole new file that holds this shared logic and each util function, and exports them. Then, each component separately imports them. That ensures that if you ever update that logic it affects both components

Brian
  • 121
  • 2
1

You can use React.createRef for this purpose. Below is an example code.

import Speech from './Speech';

type Props = {}
type States = {}
export default class SpeechIOS extends Component<Props, States> {
    constructor(props: Props) {
        super(props);
        this.speech = React.createRef();
    }

    // render
    render() {
        ...
        return (<Speech ref={this.speech} team="1" onSpeechResults={this.onSpeechResults}></Speech>);
    }

    sayHello() {
        console.log("Hello!!");
    }

    // I want that Speech Component call this onSpeechResults function
    onSpeechResults(result: string) {
        this.setState({ ...});
        let temp = this.speech.current.getMatchedSpell(... ); // which is in Speech Component
        this.sendCommand(10, 100 ... ); // which is in Speech Component
        this.sayHello(); // which is in SpeechIOS component only
        ...other things..
    };
}
TopW3
  • 1,477
  • 1
  • 8
  • 14