Search code examples
javascriptreactjsreact-context

Unable to change form text input value using react context api


I'm using the react context API to help with state management and I'm able to set form input values on page load, but I cannot change the values. When I type anything to an input the text will not change. I'm not quite sure how to bind input values to the state managed through the context api. Thanks

import React from 'react';
import * as ReactDOM from "react-dom/client";

const defaultComponentState = {
    data: {
        input_1: 123,
    }
}

const componentStateFuncs = {
    funcs: {
        updateInput1: (val) => {},
    }
}
const MyComponentDataContext = React.createContext({...defaultComponentState,...componentStateFuncs})


const myComponentDataReducer = (state, action) => {
    if (action.type === "UPDATE_INPUT_1") {
        state.data.input_1 = action.val
    }
    return state
}


const MyComponentDataProvider = (props) => {
    let [componentState, dispatchComponentAction] = React.useReducer(myComponentDataReducer, defaultComponentState)

    const updateInput1Value = (val) => {
        dispatchComponentAction({type: "UPDATE_INPUT_1", val: val})
    }
    const componentContext = {
        funcs: {
            updateInput1: updateInput1Value,
        },
        data: {
            input_1: componentState.data.input_1,
        }
    }
    console.log(`State in MyComponentDataProvider: ${JSON.stringify(componentState)}`)
    return (
        <MyComponentDataContext.Provider value={componentContext}>
            {props.children}
        </MyComponentDataContext.Provider>
    )
}


const MyComponent = (props) => {
    const myComponentCtx = React.useContext(MyComponentDataContext);

    const input1Handler = (event) => {
        myComponentCtx.funcs.updateInput1(event.target.value);
    }

    const submitForm = (event) => {
        props.onSubmitSearch(myComponentCtx.data)
    }

    return (
        <div id="my_component">
            <form onSubmit={submitForm}>
                <div>
                    <label htmlFor="input_1">Input 1</label><br/>
                    <input name="input_1" type="number" onChange={input1Handler} value={myComponentCtx.data.input_1}></input>
                </div>
                <div>
                    <button id="myComponentSubmit" className="btn btn-outline-light" type="submit">Submit</button>
                </div>
            </form>
        </div>
    )
}


const App = () => {
    const handleSubmitForm = async (params) => {
        console.log(`State in handleSubmitForm: ${JSON.stringify(params)}`)
    };

    return (
        <div id="app-container">
            <MyComponentDataProvider>
                <div id="mycomponent-container">
                    <MyComponent 
                        onSubmitSearch={handleSubmitForm}>
                    </MyComponent>
                </div>
            </MyComponentDataProvider>
        </div>
    );
}

const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
root.render(<App  />);

Solution

  • 1-Updating State in Reducer:

    const myComponentDataReducer = (state, action) => {
      if (action.type === "UPDATE_INPUT_1") {
        return {
          ...state,
          data: {
            ...state.data,
            input_1: action.val,
          },
        };
      }
      return state;
    };
    

    2-Debugging Component State:

    const input1Handler = (event) => {
      myComponentCtx.funcs.updateInput1(event.target.value);
      console.log(`Updated Input 1 Value: ${event.target.value}`);
    };