0

Back again with another react question!

UserInfoStep.js (Child)

    function UserInfoStep({ PUID, FirstName, handleChangeParent }) {
    const { dispatch } = useContext(ContactFormContext);

    return (
        //some controls

        <FormControl>
            <Grid container spacing={3}>

                <Grid item xs={12}>
                    <TextField required label="PUID"
                        style={{ width: '100%' }}
                        name="PUID"
                        onChange={e =>
                            dispatch({ type: "PUID", payload: e.target.value })
                        }
                        value={PUID} variant="outlined" />
                </Grid>
            </Grid>

            <Grid item xs={12} md={6}>
                <TextField
                    required
                    style={{ width: '100%' }}
                    label="First Name"
                    name="FirstName"
                    onChange={e =>
                        dispatch({ type: "FIRST_NAME_CHANGE", payload: e.target.value })
                    }
                    value={FirstName}

                    variant="outlined"
                />
            </Grid>
        </FormControl>
    );
}

export default UserInfoStep;

ContactForm.js (Parent)

    const initialState = {
    PUID: "",
    FirstName: "",
    total: 0
    //other params removed
};

function formReducer(state, action) {
    switch (action.type) {
        case "PUID":
            fetch('https://api.npms.io/v2/search?q=react')
                .then(result => result.json())
                .then(data => {

                    console.log(data.total);
                });
            return { ...state, PUID: action.payload };
        case "FIRST_NAME_CHANGE":
            return { ...state, FirstName: action.payload };
        default:
            throw new Error();
    }
}

function ContactForm() {
    const { PUID, FirstName, total } = state;


    const steps = [
        <UserInfoStep handleChangeParent={handleChange} {...{ PUID, FirstName }} />,
    ];

    return (
        <ContactFormContext.Provider value={{ dispatch }}>
    //some code removed

        </ContactFormContext.Provider>
    );
}

export default ContactForm;

I want to set the value returned from the API call (data.total), in the FirstName input box when PUID onChange triggers. The API call can also be moved to the Child (UserInfoStep) if needed.

Edit

I have now moved my API call to UserInfoStep.js

const onPUIDChanged = (event) => {    
fetch('https://api.npms.io/v2/search?q=react')
  .then(result => result.json())
  .then(data => {        
    console.log(data.total);
  });
dispatch({ type: "PUID", payload: event.target.value });            
};


<Grid item xs={12}>
      <TextField required label="PUID"
      style={{width:'100%'}}
      name="PUID"
      onChange={onPUIDChanged}
      value={PUID} variant="outlined"/>
    </Grid>
Samra
  • 1,815
  • 4
  • 35
  • 71
  • Reducers are not async so you have to use [thunk](https://github.com/reduxjs/redux-thunk) for redux or dispatch after fetch when you used useReducer (not clear what you are using). When you set async result on user input make sure you set the [last async result](https://stackoverflow.com/a/62751846/1641941). – HMR Oct 27 '21 at 06:33

1 Answers1

1

Don't use API call in your reducer, the reducer is just a function that gets an action and returns the state.

The philosophy of using action - reducer - store in redux architecture is to separate the logic.

There are two options for you:

  1. using a third library like redux-saga to control the async API calling and handle the side effects with the power of generators.

  2. call the API in your component/page and then dispatch the proper action for success/failure cases.

nima
  • 7,796
  • 12
  • 36
  • 53