我有一个使用firebase和reactjs / nodejs的单页应用程序,该应用程序更新/删除/添加了html代码(正文和描述)。该功能可以正常工作,并且数据将在数据库中进行相应更新。但是,一旦执行任何功能(仅当我手动按F5时),列表就不会刷新。我希望列表在添加/编辑/删除任何内容时动态更改。我怎样才能做到这一点? 这是我的代码:
HTML.js:
const updateByPropertyName = (propertyName, value) => () => ({
[propertyName]: value,
});
class HTML extends Component {
constructor(props) {
super(props);
this.state = {
html: []
};
}
componentDidMount() {
db.onceGetHTML().then(snapshot =>
this.setState(() => ({ html: snapshot.val() }))
);
}
render() {
const { html } = this.state;
const { description } = this.state;
const { body } = this.state;
return (
<div>
<h1>Home</h1>
<p>The Home Page is accessible by every signed in user.</p>
<input value={description}
onChange={event => this.setState(updateByPropertyName('description', event.target.value))}
type="text"
placeholder="Description..."
/>
<input value={body}
onChange={event => this.setState(updateByPropertyName('body', event.target.value))}
type="text"
placeholder="Body..."
/>
<button onClick={() => addHTML(description, body)}>Add Content</button>
{!!html && <HTMLList html={html} />}
</div>
);
}
}
这些全都放在一个文件中,我只是将它们拆分以使其易于阅读(HTML.js):
function addHTML(description, body, callback) {
addAnHTML(description, body);
}
这是同一文件中的第二个类,负责显示项目列表:
class HTMLList extends Component {
constructor(props) {
super(props);
this.state = {
BODY: '',
desc: '',
html: ''
};
}
render() {
const { html } = this.props;
const { desc } = this.state;
const { BODY } = this.state;
return (
<div>
<h2>List of HTML available:</h2>
{Object.keys(html).map((key, index) =>
<div>
{index + 1}.
{html[key].description}
<img src="http://www.stilltimecollection.co.uk/images/english/b_delete.gif" onClick={() => deleteHTML(key)} />
<Popup trigger={<img src="https://www.faktorzehn.org/de/wp-content/uploads/sites/2/2015/03/f10-org-new_3_6_0-edit.gif" />
} position="right center">
<div>
<input value={desc}
onChange={event => this.setState(updateByPropertyName('desc', event.target.value))}
type="text"
placeholder="Descripton.."
/>
<input value={BODY}
onChange={event => this.setState(updateByPropertyName('BODY', event.target.value))}
type="text"
placeholder="Body..."
/>
<button onClick={() => updateHTML(key, desc, BODY)}>Update Content</button>
</div>
</Popup>
<br></br>
</div>
)}
</div>
);
}
}
函数addAnHTML位于数据库同步的另一个文件中:
export const addAnHTML = (description, body) => {
var html =
{
description: description,
body: body,
created_at: format.asString(),
updated_at: ""
}
db.ref('Content').push(html);
alert("Content Added");
}
我的页面如下所示: https://preview.ibb.co/fTwiaT/Untitled.png
我的数据库如下所示(已添加到db中,但不是动态添加的): https://image.ibb.co/nNEapo/database.png
编辑:所以这是我使用的功能的修改:
export const onceGetHTML = () =>
db.ref('Content').once('value');
export const addAnHTML = (description, body) => {
console.log(description);
console.log(body);
var html =
{
description: description,
body: body,
created_at: format.asString(),
updated_at: ""
}
db.ref('Content').push(html);
}
和我班上经过编辑的添加函数如下:
addContent(description, body) {
this.setState({
html: [
...this.state.html,
{
description: this.state.description,
body: this.state.body
}
]
});
addAnHTML(this.state.description,this.state.body);
}
Snapshot.val()包含我的“内容”父级的所有子级值: https://preview.ibb.co/jetOc8/edit.png
答案 0 :(得分:0)
我将展示如何使用“添加”功能将数据正确映射到DOM。
这是经过修改的HTML类
export class HTML extends Component {
constructor(props) {
super(props);
this.state = {
html: [],
// if you keep your user inputted data in the DOM state, it's good to initialize them first, otherwise your component will suddenly change from an uncontrolled component to a controlled component.
description: "",
body: ""
};
}
componentDidMount() {
// EDIT: code here for initializing `html`
db.onceGetHTML().then(snapshot =>
// EDIT: it's simpler to just call setState with the new state object you want
this.setState({ html: snapshot.val()})
);
}
// use class methods to update your DOM state, because inside these methods
// also don't forget to call your API here
addContent(description, body) {
// EDIT: make sure to make your call to the db for adding an entry
this.setState({
// please keep in mind that you should NEVER mutate your state, so in here I'm using the spread operator to create a new array instance
// this is appending a new entry to the old "html"
html: [
...this.state.html,
{
description: this.state.description,
body: this.state.body
}
]
});
}
// use this to update the state for each input field
updateByPropertyName(property, e) {
this.setState({
[property]: e.target.value
});
}
render() {
const { html } = this.state;
const { description } = this.state;
const { body } = this.state;
return (
<div>
<h1>Home</h1>
<p>The Home Page is accessible by every signed in user.</p>
<input
value={description}
onChange={this.updateByPropertyName.bind(this, "description")}
type="text"
placeholder="Description..."
/>
<input
value={body}
onChange={this.updateByPropertyName.bind(this, "body")}
type="text"
placeholder="Body..."
/>
// this onClick event will call "this.setState(...)" which will trigger the re-render (or the "refresh" you are looking for)
<button onClick={this.addContent.bind(this)}>Add Content</button>
{!!html && <HTMLList html={html} />}
</div>
);
}
}
这足以成功重新渲染。
另一方面,在列表中为元素建立索引也很有用。这对于React进行有效渲染非常有用。为此,您可以像这样修改HTMList类:
//...
<h2>List of HTML available:</h2>
{Object.keys(html).map((key, index) => (
// using the index parameter supported in the .map callback it's okay
// because it makes your DOM list nodes predictable and easy for React to re-render
<div key={index}>
{index + 1}.
{html[key].description}
<img
//...
对于更新和删除,您可以遵循相同的模式,仅相应地更改状态(保持html
对象的状态)。
您可以将这些读数用于我上面刚刚解释的内容