3

I am using react with typescript. I have a function that returns a component in jsx:

function TestComponent(str: string) {
    return <span>Hello, your string was {str}</span>
}

Assuming that function is reasonable (is it?), how do I call it within more jsx code?

I have tried:

  <TestComponent str="abcde" />
  <TestComponent str={'abcde'} />
  <TestComponent {'abcde'} />
  <TestComponent {str:'abcde'} />

But I suspect I'm missing something more fundamental about how function parameters are passed around (I'm very new to both react and typescript).

Thanks.

Jer
  • 5,468
  • 8
  • 34
  • 41
  • 3
    I don't have time to write a full answer, but what you've made is a component, and the first argument is the `props` object. If you change the signature to `TestComponent({ str })` (i.e. use destructuring) then it should work. I'll leave typing that up to you... there are differing views around how to type props in functional components. – david Sep 15 '20 at 23:41

2 Answers2

5

You're pretty close, the problem you're facing is that props are an object even when you're passing a single item.

interface TestComponentProps {
   str: string;
}
function TestComponent({str}: TestComponentProps) {
    return <span>Hello, your string was {str}</span>
}

You then call it with either of the following syntaxes:

<TestComponent str='abcde' />
<TestComponent str={'abcde'} />

str={'abcde'} just means that React should evaluate 'abcde'. Since it's a string literal, nothing changes. However, this has an important caveat, string literals do not have any HTML-escaping applied. So you must do this handling yourself.

The React documentation does a good job at explaining what is happening under the hood here. But in short, JSX is just syntatic sugar and these are the equivalent of writing:

React.createElement(TestComponent, {str: 'abcde'}, null);

From this, you can probably guess what happens if we were to add a second prop.

interface TestComponentProps {
   str: string;
   coolString: string;
}
function TestComponent({str, coolString}: TestComponentProps) {
    return <span>Hello, your string was {str} and your coolString was {coolString}</span>
}

<TestComponent str="abcde" coolString={'fghi'}/>

So, what's the third parameter? That's for children. Typing for children was stolen from this answer. Let's see it in action.

interface TestComponentProps {
   str: string;
   children: React.ReactNode
}
function TestComponent({str, children}: TestComponentProps) {
    return (<>
               <span>Hello, your string was {str}</span>
               <div>
                  {children}
               </div>
            </>);
}

<TestComponent str={'<3'}>
   <p>Hey there! 1 + 1 = {1 + 1}</p>
   <p>I'm another child!</p>
</TestComponent>

Becomes:

function TestComponent({
  str,
  children
}) {
  return React.createElement(React.Fragment, null, React.createElement("span", null, "Hello, your string was ", str), React.createElement("div", null, children));
}


React.createElement(TestComponent, {
  str: '<3'
}, React.createElement("p", null, "Hey there! 1 + 1 = ", 1 + 1), React.createElement("p", null, "I'm another child!"));

Note: The <> </> syntax is called a Fragment and is essentially a grouping function that has no DOM output.

Digital Deception
  • 2,677
  • 2
  • 15
  • 24
1

Try making your function accept a props object as the parameter and use {props.str} in the span element. Or de-structure the str prop in the parameter.

Harsha Limaye
  • 915
  • 9
  • 29