The value value is not an instance variable


#1

Hi all
I wrote a component, that should only accept numbers:

type state = {inputValue: string};

type action =
  | OnKeyPress(string);

let component = ReasonReact.reducerComponent("NumberInput");

let make = (value: string, _children) => {
  ...component,
  initialState: () => "",
  reducer: (action, _state) =>
    switch (action) {
    | OnKeyPress(v) =>
      UtilWrapper.acceptOnlyNumbers(v) ?
        ReasonReact.UpdateWithSideEffects(
          {inputValue: v},
          (
            self => {
              value = self.state.inputValue;
              ();
            }
          ),
        ) :
        ReasonReact.NoUpdate
    },
  render: self =>
    <input
      type_="text"
      value=self.state.inputValue
      onKeyPress=(
        event =>
          self.send(
            OnKeyPress(
              ReactDOMRe.domElementToObj(ReactEventRe.Keyboard.target(event))##value,
            ),
          )
      )
    />,
};  

and the compiler complains:

  We've found a bug for you!
  /home/developer/Desktop/reason-react/cockpit/src/Input/NumberInput.re 19:15-43

  17 ┆ (
  18 ┆   self => {
  19 ┆     value = self.state.inputValue;
  20 ┆     ();
  21 ┆   }

  The value value is not an instance variable

ninja: build stopped: subcommand failed.
>>>> Finish compiling(exit: 1)  

What am I doing wrong?

Thanks


#2

You are trying to bind a value to something that is not a variable.
I think you don’t need also the side effect, this should work probably

type state = {inputValue: string};

type action =
  | OnKeyPress(string);

let component = ReasonReact.reducerComponent("NumberInput");

let make = (value: string, _children) => {
  ...component,
  initialState: () => {inputValue: string},
  reducer: (action, _state) =>
    switch (action) {
    | OnKeyPress(v) =>
      UtilWrapper.acceptOnlyNumbers(v) ?
        ReasonReact.Update({inputValue: v}) : ReasonReact.NoUpdate
    },
  render: self =>
    <input
      type_="text"
      value=self.state.inputValue
      onKeyPress=(
        event =>
          self.send(
            OnKeyPress(
              ReactDOMRe.domElementToObj(ReactEventRe.Keyboard.target(event))##value,
            ),
          )
      )
    />,
};  

#3

shouldnt the initialState be like this:

initialState: () => { inputValue: "" }
(not trying to correct, just asking out of curiosity :slight_smile: )


#4

I changed the coding to:

type state = {inputValue: string};

type action =
  | OnKeyPress(string);

let component = ReasonReact.reducerComponent("NumberInput");

let make = (_children) => {
  ...component,
  initialState: () => {inputValue: ""},
  reducer: (action, _state) =>
    switch (action) {
    | OnKeyPress(v) =>
      Js.log(v);
      UtilWrapper.acceptOnlyNums(v) ?
        ReasonReact.Update({inputValue: v}) : ReasonReact.NoUpdate
    },
  render: self =>
    <input
      type_="text"
      value=self.state.inputValue
      onKeyPress=(
        event =>
          self.send(
            OnKeyPress(
              ReactDOMRe.domElementToObj(ReactEventRe.Keyboard.target(event))##value,
            ),
          )
      )
    />,
};

the action onKeyPress send an empty value. The action happen on this:

| OnKeyPress(v) =>
  Js.log(v);  

How to the the value from the input?

Thanks


#5

ReactEventRe.Keyboard.target does not return the value in this case. I dont know why :open_mouth:

You can use onChange with ReactEventRe.Form Event instead:

onChange=(
        event =>
          self.send(
            OnKeyPress(
              ReactDOMRe.domElementToObj(ReactEventRe.Form.target(event))##value,
            ),
          )
      )

If you need the pressed key code, you can use onKeyDown simultaneously.

onKeyDown=(
   _event => {
      let pressedKey = ReactEventRe.Keyboard.key(_event);
      ...

#6

state in ReasonReact could be any type, not just a record.


#7

indeed! forgot it was a record