BARNOWL
BARNOWL

Reputation: 3589

custom useEffect hook is not accessible in other components

I'm trying to make this hook resuable through out my application.

This hook retrieves the posts api, i want to be able to call this hook on other pages.

postsHook.tsx

import React, { useEffect, useRef } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
    addContent,
    addTitle,
    createPostInit,
    deleteCommentInit,
    initCommentUpdates,
    deletePostInit,
    dislikePostInit,
    getPostsInit,
    likePostInit,
    notificationInit,
    postCommentInit,
} from "../../actions/postActions";
import { getBodyError, getIsNotified, getNotification, getPopPosts, getPosts, getTitleError, getUser, postContent, title } from "./../../selectors/selectors";
const mapDispatchToProps = (dispatch: any) => ({
    getPostsInit: () => dispatch(getPostsInit()),
    initCommentUpdates: () => dispatch(initCommentUpdates()),
    notificationInit: () => dispatch(notificationInit()),
    likePost: (id: number) => dispatch(likePostInit(id)),
    addTitle: (data: string) => dispatch(addTitle(data)),
    addContent: (data: string) => dispatch(addContent(data)),
    postCommentInit: (commentData: object) => dispatch(postCommentInit(commentData)),
    dislikePost: (id: number) => dispatch(dislikePostInit(id)),
    deletePostInit: (id: number, userId: number) => dispatch(deletePostInit(id, userId)),
    deleteComment: (id: number, postId: number, userId: number) => dispatch(deleteCommentInit(id, postId, userId)),
    createPostInit: (postData: object) => dispatch(createPostInit(postData)),
});

const mapStateToProps = createStructuredSelector({
    posts: getPosts(),
    popPosts: getPopPosts(),
    user: getUser(),
    isNotified: getIsNotified(),
    titleError: getTitleError(),
    bodyError: getBodyError(),
    title: title(),
    postContent: postContent(),
    notification: getNotification(),
});

function PostsHooks(props) {
    const didMountRef = useRef<Object>();
    React.useEffect(() => {
        if (!didMountRef.current) {
            props.getPostsInit();
            props.initCommentUpdates();
            console.log("test");
        } else {
            console.log("this is component didupdate");
        }
    }, []); // array prevents an infinite loop
    return null;
}

export default connect(mapStateToProps, mapDispatchToProps)(PostsHooks);

I want to call this hook in landing component, however im gettting

NOTE: Exotic components are not callable.

Expected 1 arguments, but got 0.ts(2554) index.d.ts(323, 10): An argument for 'props' was not provided.

What am i doing wrong ?

Landing.tsx

import React, { Fragment, useRef, Component } from "react";
import PostList from "../forms/postList/postList";
import GridHoc from "../hoc/grid";
import Typography from "@material-ui/core/Typography";
import PostsHook from "./../common/postsHook";
function Landing(props) {
    const [posts] = PostsHook();
    // const didMountRef = useRef<Object>();
    // React.useEffect(() => {
    //     if (!didMountRef.current) {
    //         props.getPostsInit();
    //         props.initCommentUpdates();
    //         console.log("test");
    //     } else {
    //         console.log("this is component didupdate");
    //     }
    // }, []); // array prevents an infinite loop

    return (
        <Fragment>
            <Typography variant="h6" align="left">
                Post's from our users
            </Typography>
            {/* <PostList
                likePost={props.likePost}
                deletePost={props.deletePostInit}
                deleteComment={props.deleteComment}
                dislikePost={props.dislikePost}
                posts={props.posts}
                currentUser={props.user}
                postComment={props.postCommentInit}
                isNotified={props.isNotified}
                getNotifications={props.notificationInit}
                notification={props.notification}
            /> */}
        </Fragment>
    );
}
export default GridHoc(Landing);

Upvotes: 0

Views: 399

Answers (1)

Agney
Agney

Reputation: 19194

From react docs:

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks

So the first step would be to change the naming to:

function usePostsHook() {
  ...
}

const Landing() {
  usePostsHook();
  ...
}

A connect function from redux is used on components and since a custom hook is not a component, you cannot use it there. Luckily, redux ships with two custom hooks: useSelector and useDispatch to provide the same functionality.

useSelector useDispatch

function usePostsHook() {
  // getPosts would have to be a fn that takes store and returns posts.
  const posts = useSelector(getPosts());
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(getPostsInit());
    dispatch(initCommentUpdates());
  }, []);
  return [posts];
}

const Landing() {
  const [posts] = usePostsHook();
  ...
}

On the API side, note that you are trying to return posts from the hook, but the hook is infact returning null

Upvotes: 2

Related Questions