skip to Main Content

I have a slice file that includes an async thunk function that returns an array based on API response. Some of this array elements are some i tags that trigger some functions to do something inside another component that is going to dispatch an async thunk. I don’t know how can I call these functions (handleShowForm and handleShowHistory) when this slice file is not a child of that component that has the definition of these functions. I mean I can’t pass them through props or contexts.

slice.js:

export const getNomads = createAsyncThunk("applicant/getNomads", async(data) => {
  const {
    searchParam,
    pageNum
  } = data

  let nomadObj = {
    isPending: true,
    bodyArray: []
  }

  await axios.get(`https://demo.khedmatashayer-kj.ir/api/v1/nomad/${pageNum}?${searchParam}`, config)
    .then((response) => {
      ...
      let array = [];
      response.data && response.data.forEach((item) => {
        array = [...array, [ <i className="fa fa-edit edit"
          onClick={
            () => handleShowForm(item)
          }></i>, <i className="fa fa-file-text-o records"
          onClick={
            () => handleShowHistory(item.name, item.nomad_id)
          }></i>,
          ...
        ], ];
      });
      nomadObj = {
        isPending: false,
        bodyArray: array
      }
    })
  return nomadObj;
})

const applicantSlice = createSlice({
  ....
  }
})

My component:

const MyComponent = () => {

  const handleShowForm = (arg) => {
    ..
  }

  const handleShowHistory = (arg1, arg2) => {
    ..
  }

  useEffect(() => {
    dispatch(getNomads({
      searchParam: '',
      pagaNum: 1
    }))
  });

}

2

Answers


  1. Well it looks like you need a state manager in react the most popular are react context, react redux or zustand.

    So you would need to manipulate the same value inside the functions.

    For example:

    const handleShowForm = (arg) => {
        setVisible(true)
        .
        .
    }
    

    Then in the createAsyncThunk in onClick you would call the same:

    onClick={() => setVisible(true}
    

    Where setVisible is a context exposed constant.

    Context: https://react.dev/reference/react/createContext

    Zustand: https://github.com/pmndrs/zustand

    This is one way, another one is to create a new file called helper.js and write the handleShowForm & handleShowHistory in there. Make sure you export them so you are able to call them in your files.

    Login or Signup to reply.
  2. You are storing JSX in state, this is a React anti-pattern. You should be storing the data into state, and selecting it in the UI and then render it to JSX at run-time where the callback functions are in scope.

    Example Refactor:

    Update the applicantSlice to handle the fulfilled getNomads action.

    export const getNomads = createAsyncThunk(
      "applicant/getNomads",
      async({ searchParam, pageNum }, thunkApi) => {
        try {
          const { data } = await axios.get(
            `https://demo.khedmatashayer-kj.ir/api/v1/nomad/${pageNum}?${searchParam}`,
            config
          );
          return data;
        } catch(error) {
          return thunkApi.rejectWithValue(error);
        }
      }
    );
    
    const applicantSlice = createSlice({
      ...,
      extraReducers: builder => {
        builder
          .addCase(getNomads.pending, (state) => {
            state.isPending = true;
          })
          .addCase(getNomads.fulfilled, (state, action) => {
            state.nomads = action.payload;
            state.isPending = false;
          })
          .addCase(getNomads.rejected, (state, action) => {
            state.error = action.payload;
            state.isPending = false;
          });
      },
    });
    

    Update MyComponent to select the state and map the nomads to the i tags.

    import { useDispatch, useSelector } from 'react-redux';
    
    const MyComponent = () => {
      const dispatch = useDispatch();
      const { isPending, nomads } = useSelector(state => state.applicant);
    
      const handleShowForm = (arg) => {
        ...
      };
    
      const handleShowHistory = (arg1, arg2) => {
        ...
      };
    
    
      useEffect(() => {
        dispatch(getNomads({
          searchParam: '',
          pagaNum: 1
        }));
      }, []); // <-- don't forget dependency array!!
    
      if (isPending) {
        return /* some loading UI */;
      }
    
      return (
        ...
    
        {nomads.map(nomad => (
          <React.Fragment key={nomad.nomad_id}>
            <i
              className="fa fa-edit edit"
              onClick={() => handleShowForm(nomad)}
            />
            <i
              className="fa fa-file-text-o records"
              onClick={() => handleShowHistory(nomad.name, nomad.nomad_id)}
            />
          </React.Fragment>
        ))}
    
        ...
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search