How to make a simple post and reply system with React, Firebase, Redux

Hi ! Today we meet to see how to make a simple post and reply system with React, Firebase, Redux

Want to see how he behaves?

  • Create post
  • Read post
  • Click on the post which redirects to a link, displaying the post and its responses.
  • Write responses to this post

Here is the structure of the files:

src 
  └──app
     └── components 
        ├── CreatePost.js
        ├── ListPost
        ├── ShowPost.js
        ├── InPost.js
        ├── Reply.js
  └──store
     ├── store.js
     ├── PostSlice.js

   ├── app(router).js

Are you ready ? 👉

Packages

First, you will need to install all the necessary packages.

🤘 Redux 
    "@reduxjs/toolkit": "^1.6.2"
    "react-redux": "^7.2.6"

🔥 Firebase
    "firebase": "^9.5.0"
    "react-firebase-hooks": "^4.0.1"

⬅⬇➡ Router 
"react-router": "^5.2.1"
"react-router-dom": "^5.3.0"

If you haven't set up your router yet, it should look like this:

Router.js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

<Router>
         <Switch>
          <Route exact path="/blabla" component={blabla} />
        </Switch>
        </div>
</Router>

➕ Create a post

Now, we will create a file which will be called CreatePost.js
We are going to create a new function which will be called sendPost. Whit Firestore, we will create a new document in the post collection.
In it, we will put different fields including title and message, which will be the value of the inputs and the others the user's information.

const  inputTitle = useRef(""); 
    const inputMessage = useRef("");

    const db = firebase.firestore();
    const sendPost = useCallback(async event => {
        event.preventDefault();
        if (inputTitle.current.value !== "") {
            db.collection("post").add({
              timestamp: firebase.firestore.FieldValue.serverTimestamp(),
              title: inputTitle.current.value,
              message: inputMessage.current.value,
              name: user.displayName,
              photoURL: user.photoURL,
            }); 
        }
    })

    return (
/* the onSubmit will execute the "sendPost" function. */    
   <form onSubmit="sendPost">
    <input
    ref={inputTitle}
    placeholder="Title"
    >
    <input
    ref={inputMessage}
    placeholder="Message"
    >
    <button type="submit">
    </form>
    )

When you go to Firestore console.firebase.google.com, it would look like this:

📖 Read a post

Now, we will move on to the second step: 📚 Display the posts.

To do this, start by creating a file named ListPost.

With the useCollection function, we can choose any collection. For this case, we're going to use the 'post' collection. Then, we will make a docs.map, where we will put all the fields.

To be able to read the messages, we will create a file named 'ShowPost', we will display the messages inside.

import { useCollection } from "react-firebase-hooks/firestore"
import ShowPost from './ShowPost.js'
    const db = firebase.firestore();
    const [postlist] = useCollection(
      db
      .collection("post")
      );  

return( 

/* Don't forget to keep the key and the id, it will be important for the future. */

       {postlist?.docs.map((doc) => (

  <MessageShow
  key={doc.id}
  id={doc.id}
  title={doc.data().title}
  name={doc.data().name}
  photoURL={doc.data().photoURL}
  />
))}

)
ShowPost.js

We will import everything we put in the MessageShow, then we just have to use {blabla} so that the text of the field is displayed.

function ShowPost({id, title, name, photoURL}) {

return (
<img src={photoURL}>
<p> {title} </p>
<p> {name} </p>
)

🚗 Redux joined the chat

Create a new Store folder. In it, you will create a file named 'Store.js'. We will inserted given a small-code

/* We import the configureStore from redux */
import { configureStore } from "@reduxjs/toolkit";
import postSlice from "./PostSlice";
export const store = configureStore({
  reducer: {
    post: postSlice,
  },
});

Then you create a new file 'PostSlice.js'

import { createSlice } from "@reduxjs/toolkit";

/* We define the initial state */
const initialState = {
  postId: null,
};

export const postSlice = createSlice({
  name: "post",
  initialState,
  reducers: {
    setPost: (state, action) => {
      state.postId = action.payload.postId;
      state.postName = action.payload.postName;
    },
  },
});

export const { setPostInfo } = postSlice.actions;

export const selectPostId = (state) => state.post.postId;
export const selectPostName = (state) => state.post.postName;

export default postSlice.reducer;

We modify our ' index.js '

/* We import our redux tools */

import { Provider } from "react-redux"
import { store } from "./store/Store"

/* We add a provider */

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
    <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

Now, we come back to our MessageShow.js file

function ShowPost({id, title, name, photoURL}) {
 const setPost = () => {
        dispatch(
          setPostInfo({
            postId: id,
          })
        );

        history.push(`/post/{$id}`);
      };
return (

/* We now add a div, and when we click on it, it executes the 'setPost' function
We also define the cursor as a pointer
*/

<div onClick={setPost} style={{cursor: 'pointer'}}>
<img src={photoURL}>
<p> {title} </p>
<p> {name} </p>
</div>
)

We now come back to our app (router.js)

/* You just add these two little lines.
Thanks to what we have not added in index.js, we can freely put the id in the router. When it is on the url /post /id/, it will display the component 'InPost.js'
*/

import InPost from './InPost.js'
return ( 
          <Route exact path="/post/message/:id" component={InPost} />
)

📜 InPost

Create a new file named InPost.js

/* We import all the features */

import { useCollection } from "react-firebase-hooks/firestore"
import { selectPostId } from  './store'
import { useSelector } from "react-redux";

fonction InPost(){
    const db = firebase.firestore();
    const postId  = useSelector(postId);
/* The code is almost identical to MessageShow.js, it's just that we add a .doc(postId)*/
    const [InPostShow] = useCollection( 
      db
      .collection("front-message")
      .doc(postId)
      );
return ( 

{InPostShow?.docs.map((doc) => {
         const { title, message, photoURL, name} = doc.data()

       return (            
<p>{tile}</p>
<p>{message}</p>
  );
})}


    )
}

📰 Reply

The system is really the same as CreatePost.js and ShowMessage.js

🥖 Et voilà !

You've finished your post and reply system
, now all you have to do is put css ✨?

Donations-Support

Bitcoin Ethereum
3FahtNWC4tmZh1B72vz44TvBN2jHaQSnh4 0x7cad12dfd11bce3f29b96260b4739caa32c89a86

24