React: How to supply callback arrow functions to stateless functional child components?

I'm struggling to supply a callback function to a stateless functional child component. I have these two components:

export const FrontDeskGUI = () => {
    const callback = (event) => console.log(event.target.value);
    return (
        <Col xs={12}>
            <Panel collapsible defaultExpanded header="Empfang">
                <ButtonGrid/>
            </Panel>
            <Panel collapsible defaultExpanded header="Verwaltung">
                <ButtonGrid/>
            </Panel>
            <CommandInput callback={callback}/>
        </Col>);
};

export const CommandInput = (callback) => {
    const style = {
        textTransform: 'uppercase'
    };
    return (
        <Col xs={12}>
            <form>
                <FormGroup
                    controlId="command">
                    <FormControl
                        type="text"
                        style={style}
                        placeholder="K&uuml;rzel eingeben"
                        onChange={callback}/>
                </FormGroup>
            </form>
        </Col>);
};

During rendering I get the following error:

Warning: Failed form propType: Invalid prop onChange of type object supplied to input, expected function. Check the render method of FormControl.

Everytime I input something into the text input, I get the following error:

Uncaught TypeError: inputProps.onChange.call is not a function at Object.executeOnChange (LinkedValueUtils.js:132)

Is this at all possible in a stateless environment? Technically the supplied callback function is constant, so there is no inherent state in the CommandInput component. I've seen some answers messing around with binding functions to the correct this pointer but I'd like to avoid that if possible.

Upvotes: 2

Views: 2711

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

The single argument your SFC receives is a properties object with a property for each property used on the component in the JSX markup.

So either accept the property and use its callback property:

export const CommandInput = (props) => {
    // ...use props.callback...
}

or use parameter destructuring:

export const CommandInput = ({callback}) => {
                          // ^--------^---------------- note { }
    // ... use callback...
}

Currently, you're trying to use the props object itself as the onChange, which is why you get the error.

Example using destructuring:

const Example = ({callback}) =>
  <div onClick={callback}>Click me</div>;

ReactDOM.render(
  <Example callback={() => console.log("Clicked")} />,
  document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Upvotes: 3

Related Questions