Search code examples
reactjsreact-context

How do I rerender a component from another competent


I have an ActivityFeed of posts. When I click on an icon in the ActivityPost component it saves the postId in a global state (EditPostIndex) that's meant to act like a toggle for the CreatePost and EditPost component in the Activity feed. When I click on the editpost icon it brings up the body of the post that I'm suppose to edit

ActivityFeed

const ActivityFeed = () => {
    const {posts} = useContext(GlobalContext);
    const {editPostIndex} = useContext(GlobalContext);
    return (
        <div id="mobile-activity">
            <DeviceNav />
            { editPostIndex === null ? 
                <CreatePost />
            :
                <EditPost />
            }
            {posts.slice(0).reverse().map(post => (
                <ActivityPost key={post.id} post={post} /> 
            ))}     
        </div>
    )
}

ActivityPost

function ActivityPost({post, index}) => {
    const {toggleEditPost} = useContext(GlobalContext);
    function updatePost(index){
        toggleEditPost(index)
    }
}

EditPost.js

const EditPost = () => {
    const {posts} = useContext(GlobalContext);
    const {updatePost} = useContext(GlobalContext);
    const {editPostIndex} = useContext(GlobalContext);
    let val = posts[editPostIndex].body;
    let [body, setBody] = useState(val);

    function editPost() {
        //update
    }
    return (
        <div  id="make-post">
            <div id="create-post">
                <textarea value={body} onChange={(e) => setBody(e.target.value)} id="post-activity" placeholder="Tell them what you think."></textarea>
            </div>
            <div id="create-post-actions">
            
                <button onClick={editPost} id="post">Edit</button>
            
            </div>
        </div>
    )
}

GlobalState/GlobalContext

const initialState = {
    posts: posts,
    editPostIndex: null
}

export const GlobalProvider = ({children}) => {
    const [state, dispatch] = useReducer(AppReducer, initialState)

    function toggleEditPost(index = null){
        dispatch({
            type: 'TOGGLE_EDIT_POST',
            payload: index
        })
        //alert(index);
    }
    function updatePost(post){
        dispatch({
            type: 'UPDATE_POST',
            payload: post
        })
        toggleEditPost(null);
    }
}

The problem is that in EditPost component let val = posts[editPostIndex].body; let [body, setBody] = useState(val); the useState only renders once because the EditPostIndex is already changed. How do I make it so when I click on the edit post icon the let [body, setBody] = useState(val); changes to the posts body that I want to edit? Or rerender the EditPost component so setBody is set again?


Solution

  • In this case, I'd say you'd need more hooks like useState & useEffect to detect a change in your context EditPost.js.

    const [postIndex, setPostIndex] = useState(editPostIndex);
    useEffect(() => {
       if(editPostIndex !== postIndex){
          setPostIndex(editPostIndex);
          setBody(posts[editPostIndex].body)
       }
    }, [setPostIndex, postIndex])