Не эксперт по базам данных, но я считаю, что ваша база данных немного странная и будет вызывать проблемы только в дальнейшем, особенно когда речь идет о редактировании / обновлении одного поста.В идеале он должен быть структурирован как массив JSON
:
posts: [
{
id: "LNO_qS0Y9PjIzGds5PW",
title: "Example title",
content: "This is just a test"
},
{
id: "LNOc1vnvA57AB4HkW_i",
title: "Example title",
content: "This is just a test"
},
...etc
]
, а не структурирован как объект JSON
:
"posts": {
"LNO_qS0Y9PjIzGds5PW": {
"post": {
"title": "Example title",
"content": "This is just a test"
}
},
"LNOc1vnvA57AB4HkW_i": {
"post": {
"title": "Example title",
"content": "This is just a test"
}
},
...etc
}
В любом случае, ваш проект должен иметьparent Posts
container-component
, который контролирует все ваше состояние и выборку данных, затем передает свой state
и класс methods
компоненту children
.Затем children
может обновлять или отображать родительский state
соответственно.
ИЛИ
Вы должны отделить свой Posts
container-component
, чтобы он либо отображал найденные сообщения, либо компонент "Записи не найдены".И затем, ваш Posts Form
компонент должен быть его собственным / неразделенным компонентом, единственная функция которого - показывать форму и отправлять ее в БД.
На ваше усмотрение и то, что, по вашему мнению, соответствует вашим потребностям.
Рабочий пример: https://codesandbox.io/s/4x4kxn9qxw (в приведенном ниже примере есть один container-component
, который используется многими детьми)
Примечание. Если вы измените posts
на пустой массив []
вместо data
в fetchData()
s this.setState()
, вы можете отобразить PostForm
в * 1042.* route!
ex: .then(({ data }) => this.setState({ isLoading: false, posts: [] }))
index.js
import React from "react";
import { render } from "react-dom";
import App from "./routes";
import "uikit/dist/css/uikit.min.css";
import "./styles.css";
render(<App />, document.getElementById("root"));
маршруты / index.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Header from "../components/Header";
import Posts from "../containers/Posts";
export default () => (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/posts" component={Posts} />
<Route path="/postsform" component={Posts} />
</Switch>
</div>
</BrowserRouter>
);
контейнеров / Posts.js
import isEmpty from "lodash/isEmpty";
import React, { Component } from "react";
import axios from "axios";
import PostsForm from "../components/postsForm";
import ServerError from "../components/serverError";
import ShowPosts from "../components/showPosts";
import Spinner from "../components/spinner";
export default class Posts extends Component {
state = {
content: "",
error: "",
isLoading: true,
posts: [],
title: ""
};
componentDidUpdate = (prevProps, prevState) => {
// check if URL has changed from "/posts" to "/postsform" or vice-versa
if (this.props.location.pathname !== prevProps.location.pathname) {
// if so, check the location
this.setState({ isLoading: true }, () => this.checkLocation());
}
};
componentDidMount = () => this.checkLocation();
checkLocation = () => {
// if the location is "/posts" ...
this.props.location.pathname === "/posts"
? this.fetchData() // then fetch data
: this.setState({ // otherwise, clear state
content: "",
error: "",
isLoading: false,
posts: [],
title: ""
});
};
// fetches posts from DB and stores it in React state
fetchData = () => {
axios
.get("firebaseURL/posts.json")
.then(({ data }) => this.setState({ isLoading: false, posts: data }))
.catch(err => this.setState({ error: err.toString() }));
};
// handles postsForm input changes { content: value , title: value }
handleChange = e => this.setState({ [e.target.name]: e.target.value });
// handles postsForm form submission
handleSubmit = event => {
event.preventDefault();
const { content, title } = this.state;
alert(`Sumbitted values: ${title} - ${content}`);
/* axios.post("firebaseURL/posts.json", { post: { title, content }})
.then(({data}) => this.setState({ content: "", posts: data, title: "" }))
.catch(err => this.setState({ error: err.toString() }))
*/
};
// the below simply returns an if/else chain using the ternary operator
render = () => (
this.state.isLoading // if isLoading is true...
? <Spinner /> // show a spinner
: this.state.error // otherwise if there's a server error...
? <ServerError {...this.state} /> // show the error
: isEmpty(this.state.posts) // otherwise, if posts array is still empty..
? <PostsForm // show the postForm
{...this.state}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
/>
: <ShowPosts {...this.state} /> // otherwise, display found posts!
);
}
компонентов / postsForm.js
import React from "react";
export default ({ content, handleSubmit, handleChange, title }) => (
<form
style={{ padding: "0 30px", width: 500 }}
className="new-post-form"
onSubmit={handleSubmit}
>
<label>
Post title
<input
style={{ marginBottom: 20 }}
className="uk-input"
type="text"
name="title"
onChange={handleChange}
placeholder="Enter post title..."
value={title}
/>
</label>
<label>
Post content
<input
style={{ marginBottom: 20 }}
className="uk-input"
type="text"
name="content"
onChange={handleChange}
placeholder="Enter post..."
value={content}
/>
</label>
<button
disabled={!title || !content}
className="uk-button uk-button-primary"
type="submit"
>
Submit
</button>
</form>
);
components / showPosts.js
import map from "lodash/map";
import React from "react";
export default ({ posts }) => (
<div className="posts">
{map(posts, ({ post: { content, title } }, key) => (
<div key={key} className="post">
<h2 className="post-title">{title}</h2>
<hr />
<p className="post-content">{content}</p>
</div>
))}
</div>
);
components / serverError.js
import React from "react";
export default ({ err }) => (
<div style={{ color: "red", padding: 20 }}>
<i style={{ marginRight: 5 }} className="fas fa-exclamation-circle" /> {err}
</div>
);