I have a discussion/post type app where members can create a Post. A Post will have a normal header, body & footer. Each post can have multiple responses, each response is also a Post. And that post can have its own responses. I have managed to get all the backend stuff sorted but how to organise this in React. I am using a Symfony backend with React front-end with web pack encore I wasn't exactly sure how I could do the recursion logic in react. When I test this out the whole browser crashes, I assume its because I dont know how to put the base condition to stop the recursion.
What I know for sure: There will always be a Parent Post, If there are no responses, the ResponseList can return an empty component
I have created a simple dummy example & the code is below:
const sampleResponses = [
{
heading: 'Response Heading 1',
body: 'Response Body 1',
footer: 'Response Footer 1'
},
{
heading: 'Response Heading 2',
body: 'Response Body 2',
footer: 'Response Footer 2'
},
{
heading: 'Response Heading 3',
body: 'Response Body 3',
footer: 'Response Footer 3'
},
];
const ResponseHandler = (props) => {
return (props.responses == []) ? null : (
<ul>
{
props.responses.map((response, index) => {
return (
<li key={index}>
<Post
heading={response.heading}
body={response.heading}
footer={response.footer}
/>
</li>
);
})
}
</ul>
);
}
const Post = (props) => {
const [heading, setHeading] = useState("");
const [body, setBody] = useState("");
const [footer, setFooter] = useState("");
const [responses, setResponses] = useState([]);
useEffect(() => {
setHeading(props.heading ?? "Default Heading");
setBody(props.body ?? "Default Body");
setFooter(props.body ?? "Default Footer");
}, [])
const getResponses = (e) => {
setResponses(sampleResponses);
}
const removeResponses = (e) => {
setResponses([]);
}
return (
<div>
<article>
<header>
<h1>{heading}</h1>
</header>
<main>
{body}
</main>
<footer>
{footer}
</footer>
</article>
<button onClick={getResponses}>
Get responses
</button>
<button onClick={removeResponses}>
Remove responses (For testing)
</button>
<ResponseHandler responses={responses} />
</div>
);
}
This is the basic Post which will have responses:
//Post.js
export default function Post(props) {
const [id, setId] = useState(0);
const [heading, setHeading] = useState("This is a dummy post heading");
const [body, setBody] = useState(
"This is dumy post body. This will be deleted later when we create & connect the API"
);
const [authorName, setAuthorName] = useState("Crow Ice");
const [avatar, setAvatar] = useState("This will be some CDN in the end");
const [posted, setPosted] = useState("Nov 23 2021 - 18:30");
const [updated, setUpdated] = useState("Nov 14 2021 - 20:00");
const [responseCount, setResponseCount] = useState(487);
const [isEditor, setIsEditor] = useState(false);
return (
<Article whiteShade="0.3">
<PostHeader
posted={posted}
updated={updated}
authorName={authorName}
responseCount={responseCount}
avatar={moonTest2}
isEditor={isEditor}
/>
<PostBody body={body} />
<PostFooter
posted="Nov 23 2021 - 18:30"
updated="Nov 23 2021 - 18:30"
authorName="Rob Hush"
avatar={moonTest2}
responseCount={responseCount}
isEditor={false}
/>
</Article>
)
}
CodePudding user response:
The problem is with the sample data that you're using. The recursion never stops because the component is using the same array every time.
The array of responses that are used in the ResponseList
component must be passed as props (or in another way but they should theoretically decrease as the recursion continues).
Each response object can be like this:
{
heading: "Response Heading 2",
body: "Response body 2",
footer: "Response Footer 2",
responses: [] // this can be used for rendering the nested responses and to stop the recursion
}
responses can be optional. In the component, you can check responses?.length
to stop or continue the recursion.
Another way to define the data is by linking the responses through ids
{
id: 1,
heading: "Response Heading 2",
body: "Response body 2",
footer: "Response Footer 2",
// this post might have some responses but they are not nested here
},
{
id: 2,
heading: "Response Heading 2",
body: "Response body 2",
footer: "Response Footer 2",
parentId: 1, // this is the response to the post with id 1
},