如何使用 ReactJs 中的键从父组件打开子组件模态
How to open child component modal from parent by using its key in ReactJs
我正在创建我的博客,我想通过单击它的编辑按钮分别编辑每个博客。
现在模式正在为各自的 id 打开,但未使用 state
值设置值。
那就是 componentwillmount
没有正常工作。
有什么建议我在这里犯了什么错误吗?这会很有帮助。
我怎样才能使用当前的代码集实现这一点。
//blog.js(父组件)
import React, {Component} from 'react';
import ReactGA from 'react-ga';
import {Card, Grid, Cell, Dialog, CardMenu, Button, CardTitle, CardText, CardActions, FABButton, Icon} from'react-mdl';
import { Container, Modal, ModalHeader, ModalBody, Form, FormGroup, Label, Input,} from 'reactstrap';
import { connect } from 'react-redux';
import { getBlog, deleteBlog, updateBlog } from '../../actions/resumeActions';
import PropTypes from 'prop-types';
import Loading from './Loading';
import Moment from 'moment';
import BlogModal from "./BlogModal";
import Pagination from "react-js-pagination";
// import EditBlog from "./EditBlog";
class Blogs extends Component{
initializeReactGA() {
ReactGA.initialize('UA-132348738-1');
ReactGA.pageview('/contact');
}
constructor(props) {
super(props);
this.state = {
modal: false,
justClicked: null,
activePage: 1,
requiredItem : null,
_id: '',
blog_short_desc: '',
blog_name: '',
blog_desc: '',
blog_image_link: '',
blog_by: '',
blog_by_author: ''
};
this.handleOpenDialog = this.handleOpenDialog.bind(this);
this.handleCloseDialog = this.handleCloseDialog.bind(this);
this.replaceModalItem = this.replaceModalItem.bind(this);
this.onTodoChange = this.onTodoChange.bind(this);
}
static propTypes = {
getBlog: PropTypes.func.isRequired,
deleteBlog: PropTypes.func.isRequired,
updateBlog: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
loading: PropTypes.object.isRequired
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.name
})
}
toggle = (id) => {
this.setState({
modal: !this.state.modal
});
}
componentWillMount() {
debugger
this.props.resume["blogs"].map((blog) => {
this.setState({
updatable : false,
_id: blog._id,
blog_short_desc: blog.blog_short_desc,
blog_name: blog.blog_name,
blog_desc: blog.blog_desc,
blog_image_link: blog.blog_image_link,
blog_by: blog.blog_by,
blog_by_author: blog.blog_by_author
});
})
}
replaceModalItem(id) {
debugger
this.setState({
modal: true,
requiredItem: id
});
debugger
}
onTodoChange = (e) => {
this.setState({
[e.target.name] : e.target.value
});
}
onSubmit = (e, id) => {
e.preventDefault();
const updatedBlog = {
blog_short_desc: this.state.blog_short_desc,
blog_name: this.state.blog_name,
blog_desc: this.state.blog_desc,
blog_image_link: this.state.blog_image_link,
blog_by: this.props.auth["user"]._id,
blog_by_author: this.props.auth["user"].name
}
//update blog via updateblog action
this.props.updateBlog(id, updatedBlog, this.props.history);
alert("Blog updated successfully!");
//close modal
e.target.reset();
this.toggle();
}
handleOpenDialog(id) {
this.setState({
openDialog: true,
OpenEditDialog: true,
justClicked: id
});
}
handleCloseDialog() {
this.setState({
openDialog: false
});
}
componentDidMount() {
this.props.getBlog();
}
onDeleteBlogClick = (id) => {
this.props.deleteBlog(id);
};
handlePageChange(pageNumber) {
this.setState({activePage: pageNumber});
}
cardDialog(blogs, user){
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<Grid style={{padding: 0, display: 'contents'}}>
{activeBlogs.map(({ _id, blog_name, blog_desc, blog_image_link, blog_by_author }) => (
<Cell col={12}>
<Dialog open={this.state.openDialog && this.state.justClicked === _id} className="open-dialog">
{blog_image_link ?
(<CardTitle style={{color: '#fff', height: '176px', backgroundImage: `url(${blog_image_link})`, backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'}}>{blog_name}</CardTitle>) :
(<CardTitle className="card-blog-title-image">{blog_name}</CardTitle>
)
}
<CardText>
{blog_desc}
</CardText>
<CardActions border>
<p style={{float:'right', fontWeight:'bold'}}>Author: {blog_by_author}</p>
</CardActions>
<CardMenu style={{color: '#fff'}}>
<FABButton onClick={this.handleCloseDialog} className="close-button" >
<Icon name="close" />
</FABButton>
</CardMenu>
</Dialog>
</Cell>
))}
</Grid>
)
}
editcardDialog(blogs, user){
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<span>
<a className="btn edit-btn-blog-post" href="#" onClick={this.toggle} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
{activeBlogs.map(({ _id, blog_short_desc, blog_name, blog_desc, blog_image_link, blog_by_author }) => (
<Modal
isOpen = {this.state.modal && this.state.requiredItem === _id}
toggle = {()=>this.toggle(_id)}
>
<ModalHeader toggle={this.toggle} style={{fontWeight: "bold"}}>
Edit your blog {this.state.blog_name}
</ModalHeader>
<ModalBody>
<Form onSubmit={e => this.onSubmit(e, this.state._id )}>
<FormGroup>
<Label for="blogHeading">Blog Heading</Label>
<Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Update one liner"
onChange={this.onTodoChange} value={blog_short_desc}/>
<Label for="blogName">Blog Name</Label>
<Input type="text" name="blog_name" id="blogName" placeholder="Update blog name"
onChange={this.onTodoChange} value={blog_name}/>
<Label for="desc1">Description </Label>
<Input type="textarea" name="blog_desc" id="desc1" placeholder="Update your blog"
onChange={this.onTodoChange} value={blog_desc}/>
<Label for="imageUrl">Image Url</Label>
<Input type="text" name="blog_image_link" id="imageUrl" placeholder="Update image url (Optional)"
onChange={this.onTodoChange} value={blog_image_link}/>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
>Edit blog</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
))}
</span>
)
}
render(){
const { blogs, loading} = this.props.resume;
const { user, isAuthenticated } = this.props.auth;
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<Container>
{loading ? (
<div><Loading/></div>
) : (
<div>
{/* blog modal */}
<BlogModal />
{/* card dialog */}
{this.cardDialog(blogs, user)}
{this.editcardDialog(blogs, user)}
<Grid style={{padding: 0}} id="todo">
{activeBlogs.map((item, i) => (
<Cell key={item._id} data-id={item._id}>
<Card shadow={5} className="cards-grid">
{item.blog_image_link ?
(<CardTitle style={{color: '#fff', height: '200px',
width: 'auto', backgroundImage: `url(${item.blog_image_link})`, backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'}}></CardTitle>) :
(<CardTitle className="card-title-image"></CardTitle>
)
}
<CardText>
<b>{item.blog_short_desc}</b>
</CardText>
<CardActions border>
<p>
<Button className="blog-read-me-button col-4" onClick={this.handleOpenDialog.bind(this, item._id)}>Read </Button>
{ isAuthenticated && (item.blog_by === user._id) ?
<span className="col=8">
<Button className="remove-btn-blog-post"
color="danger"
size="sm"
onClick= {this.onDeleteBlogClick.bind(this, item._id)} title="Delete Blog">
×
</Button>
<a className="btn edit-btn-blog-post" href="#" onClick={this.replaceModalItem.bind(this, item._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
{/* <a className="btn edit-btn-blog-post" href="#" onClick={this.handleEditOpenDialog.bind(this, item._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a> */}
</span> : null }
</p>
<p style={{ fontStyle:'italic', fontWeight:'bold'}}>By-{item.blog_by_author} <span style={{float:'right',}}>{Moment(item.date).format('Do MMMM YYYY')}</span></p>
</CardActions>
</Card>
</Cell>
))}
</Grid>
</div>
)}
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={6}
totalItemsCount={blogs.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
itemClass='page-item'
linkClass='page-link'
/>
</Container>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
auth: state.auth,
loading: state.apiCallsInProgress > 0
});
export default connect(mapStateToProps, {getBlog, deleteBlog, updateBlog }) (Blogs);
试试下面的
class EditBlog extends Component {
constructor(props) {
super(props);
this.state = {
modal: null,
requiredItem : null,
_id: '',
blog_short_desc: '',
blog_name: '',
blog_desc: '',
blog_image_link: '',
blog_by: '',
blog_by_author: ''
};
this.replaceModalItem = this.replaceModalItem.bind(this);
this.onTodoChange = this.onTodoChange.bind(this);
}
static propTypes = {
auth: PropTypes.object.isRequired,
updateBlog: PropTypes.func.isRequired,
editBlog: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.name
})
}
toggle = (id) => {
this.setState({
modal: id
});
}
componentWillMount() {
this.props.resume["blogs"].map((blog) => {
this.setState({
updatable : false,
_id: blog._id,
blog_short_desc: blog.blog_short_desc,
blog_name: blog.blog_name,
blog_desc: blog.blog_desc,
blog_image_link: blog.blog_image_link,
blog_by: blog.blog_by,
blog_by_author: blog.blog_by_author
});
})
}
replaceModalItem(id) {
this.setState({
openDialog: true,
OpenEditDialog: true,
requiredItem: id
});
}
onTodoChange = (e) => {
this.setState({
[e.target.name] : e.target.value
});
}
onSubmit = (e, id) => {
e.preventDefault();
const updatedBlog = {
blog_short_desc: this.state.blog_short_desc,
blog_name: this.state.blog_name,
blog_desc: this.state.blog_desc,
blog_image_link: this.state.blog_image_link,
blog_by: this.props.auth["user"]._id,
blog_by_author: this.props.auth["user"].name
}
//update blog via updateblog action
this.props.updateBlog(id, updatedBlog, this.props.history);
alert("Blog updated successfully!");
//close modal
e.target.reset();
this.toggle();
}
render(){
return(
<span>
<a className="btn edit-btn-blog-post" href="#" onClick={()=>this.toggle(this.state._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
<Modal
isOpen = {this.state.modal===this.state._id}
toggle = {()=>this.toggle(this.state._id)}
>
<ModalHeader toggle={()=>this.toggle(this.state._id)} style={{fontWeight: "bold"}}>
Edit your blog {this.state.blog_name}
</ModalHeader>
<ModalBody>
<Form onSubmit={e => this.onSubmit(e, this.state._id, )}>
<FormGroup>
<Label for="blogHeading">Blog Heading</Label>
<Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Update one liner"
onChange={this.onTodoChange} value={this.state.blog_short_desc}/>
<Label for="blogName">Blog Name</Label>
<Input type="text" name="blog_name" id="blogName" placeholder="Update blog name"
onChange={this.onTodoChange} value={this.state.blog_name}/>
<Label for="desc1">Description </Label>
<Input type="textarea" name="blog_desc" id="desc1" placeholder="Update your blog"
onChange={this.onTodoChange} value={this.state.blog_desc}/>
<Label for="imageUrl">Image Url</Label>
<Input type="text" name="blog_image_link" id="imageUrl" placeholder="Update image url (Optional)"
onChange={this.onTodoChange} value={this.state.blog_image_link}/>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
>Edit blog</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</span>
)
}
}
const mapStateToProps = state => ({
resume: state.resume,
auth: state.auth
})
export default connect(mapStateToProps, { updateBlog })(EditBlog);
为什么不使用父组件处理所有帖子,而将 <EditBlog /
仅用作功能组件。这是一个例子和相应的 fiddle:
const EditBlog = ({title, content, handleEdit}) => {
return (
<div classname="editblog">
<h1>{title}</h1>
<p>{content}</p>
<button onClick={handleEdit}>Edit</button>
</div>
)
}
class Blog extends React.Component {
constructor(props) {
super(props);
this.state= {
activeBlogs: [
{title: "Heading 1", content: "Content 1"},
{title: "Heading 2", content: "Content 2"}
],
editId: -1,
}
this.handleEdit = this.handleEdit.bind(this);
}
handleEdit(e) {
const {editId, activeBlogs} = this.state;
let newActiveBlogs = [...activeBlogs];
const {name, value } = e.target;
newActiveBlogs[editId]= Object.assign(newActiveBlogs[editId], {[name]: value});
if(editId >= 0) {
this.setState({
activeBlogs: newActiveBlogs
})
}
}
render() {
const {activeBlogs, editId} = this.state;
return (
<div classname="blog">
{activeBlogs.map((item, index) => {
return <EditBlog key={index} {...item} handleEdit={()=>this.setState({editId: index})} />
})}
{editId >= 0 && activeBlogs.length &&
<div classname="modal">
<h2>Edit Modal is open</h2>
<input name="title" value={activeBlogs[editId].title} onChange={this.handleEdit}></input>
<input name="content" value={activeBlogs[editId].content} onChange={this.handleEdit}></input>
<button onClick={()=>this.setState({editId:-1})}>Save</button>
</div>
}
</div>
)
}
}
ReactDOM.render(
<Blog name="Blog" />,
document.getElementById('container')
);
我正在创建我的博客,我想通过单击它的编辑按钮分别编辑每个博客。
现在模式正在为各自的 id 打开,但未使用 state
值设置值。
那就是 componentwillmount
没有正常工作。
有什么建议我在这里犯了什么错误吗?这会很有帮助。 我怎样才能使用当前的代码集实现这一点。
//blog.js(父组件)
import React, {Component} from 'react';
import ReactGA from 'react-ga';
import {Card, Grid, Cell, Dialog, CardMenu, Button, CardTitle, CardText, CardActions, FABButton, Icon} from'react-mdl';
import { Container, Modal, ModalHeader, ModalBody, Form, FormGroup, Label, Input,} from 'reactstrap';
import { connect } from 'react-redux';
import { getBlog, deleteBlog, updateBlog } from '../../actions/resumeActions';
import PropTypes from 'prop-types';
import Loading from './Loading';
import Moment from 'moment';
import BlogModal from "./BlogModal";
import Pagination from "react-js-pagination";
// import EditBlog from "./EditBlog";
class Blogs extends Component{
initializeReactGA() {
ReactGA.initialize('UA-132348738-1');
ReactGA.pageview('/contact');
}
constructor(props) {
super(props);
this.state = {
modal: false,
justClicked: null,
activePage: 1,
requiredItem : null,
_id: '',
blog_short_desc: '',
blog_name: '',
blog_desc: '',
blog_image_link: '',
blog_by: '',
blog_by_author: ''
};
this.handleOpenDialog = this.handleOpenDialog.bind(this);
this.handleCloseDialog = this.handleCloseDialog.bind(this);
this.replaceModalItem = this.replaceModalItem.bind(this);
this.onTodoChange = this.onTodoChange.bind(this);
}
static propTypes = {
getBlog: PropTypes.func.isRequired,
deleteBlog: PropTypes.func.isRequired,
updateBlog: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
loading: PropTypes.object.isRequired
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.name
})
}
toggle = (id) => {
this.setState({
modal: !this.state.modal
});
}
componentWillMount() {
debugger
this.props.resume["blogs"].map((blog) => {
this.setState({
updatable : false,
_id: blog._id,
blog_short_desc: blog.blog_short_desc,
blog_name: blog.blog_name,
blog_desc: blog.blog_desc,
blog_image_link: blog.blog_image_link,
blog_by: blog.blog_by,
blog_by_author: blog.blog_by_author
});
})
}
replaceModalItem(id) {
debugger
this.setState({
modal: true,
requiredItem: id
});
debugger
}
onTodoChange = (e) => {
this.setState({
[e.target.name] : e.target.value
});
}
onSubmit = (e, id) => {
e.preventDefault();
const updatedBlog = {
blog_short_desc: this.state.blog_short_desc,
blog_name: this.state.blog_name,
blog_desc: this.state.blog_desc,
blog_image_link: this.state.blog_image_link,
blog_by: this.props.auth["user"]._id,
blog_by_author: this.props.auth["user"].name
}
//update blog via updateblog action
this.props.updateBlog(id, updatedBlog, this.props.history);
alert("Blog updated successfully!");
//close modal
e.target.reset();
this.toggle();
}
handleOpenDialog(id) {
this.setState({
openDialog: true,
OpenEditDialog: true,
justClicked: id
});
}
handleCloseDialog() {
this.setState({
openDialog: false
});
}
componentDidMount() {
this.props.getBlog();
}
onDeleteBlogClick = (id) => {
this.props.deleteBlog(id);
};
handlePageChange(pageNumber) {
this.setState({activePage: pageNumber});
}
cardDialog(blogs, user){
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<Grid style={{padding: 0, display: 'contents'}}>
{activeBlogs.map(({ _id, blog_name, blog_desc, blog_image_link, blog_by_author }) => (
<Cell col={12}>
<Dialog open={this.state.openDialog && this.state.justClicked === _id} className="open-dialog">
{blog_image_link ?
(<CardTitle style={{color: '#fff', height: '176px', backgroundImage: `url(${blog_image_link})`, backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'}}>{blog_name}</CardTitle>) :
(<CardTitle className="card-blog-title-image">{blog_name}</CardTitle>
)
}
<CardText>
{blog_desc}
</CardText>
<CardActions border>
<p style={{float:'right', fontWeight:'bold'}}>Author: {blog_by_author}</p>
</CardActions>
<CardMenu style={{color: '#fff'}}>
<FABButton onClick={this.handleCloseDialog} className="close-button" >
<Icon name="close" />
</FABButton>
</CardMenu>
</Dialog>
</Cell>
))}
</Grid>
)
}
editcardDialog(blogs, user){
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<span>
<a className="btn edit-btn-blog-post" href="#" onClick={this.toggle} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
{activeBlogs.map(({ _id, blog_short_desc, blog_name, blog_desc, blog_image_link, blog_by_author }) => (
<Modal
isOpen = {this.state.modal && this.state.requiredItem === _id}
toggle = {()=>this.toggle(_id)}
>
<ModalHeader toggle={this.toggle} style={{fontWeight: "bold"}}>
Edit your blog {this.state.blog_name}
</ModalHeader>
<ModalBody>
<Form onSubmit={e => this.onSubmit(e, this.state._id )}>
<FormGroup>
<Label for="blogHeading">Blog Heading</Label>
<Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Update one liner"
onChange={this.onTodoChange} value={blog_short_desc}/>
<Label for="blogName">Blog Name</Label>
<Input type="text" name="blog_name" id="blogName" placeholder="Update blog name"
onChange={this.onTodoChange} value={blog_name}/>
<Label for="desc1">Description </Label>
<Input type="textarea" name="blog_desc" id="desc1" placeholder="Update your blog"
onChange={this.onTodoChange} value={blog_desc}/>
<Label for="imageUrl">Image Url</Label>
<Input type="text" name="blog_image_link" id="imageUrl" placeholder="Update image url (Optional)"
onChange={this.onTodoChange} value={blog_image_link}/>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
>Edit blog</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
))}
</span>
)
}
render(){
const { blogs, loading} = this.props.resume;
const { user, isAuthenticated } = this.props.auth;
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<Container>
{loading ? (
<div><Loading/></div>
) : (
<div>
{/* blog modal */}
<BlogModal />
{/* card dialog */}
{this.cardDialog(blogs, user)}
{this.editcardDialog(blogs, user)}
<Grid style={{padding: 0}} id="todo">
{activeBlogs.map((item, i) => (
<Cell key={item._id} data-id={item._id}>
<Card shadow={5} className="cards-grid">
{item.blog_image_link ?
(<CardTitle style={{color: '#fff', height: '200px',
width: 'auto', backgroundImage: `url(${item.blog_image_link})`, backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'}}></CardTitle>) :
(<CardTitle className="card-title-image"></CardTitle>
)
}
<CardText>
<b>{item.blog_short_desc}</b>
</CardText>
<CardActions border>
<p>
<Button className="blog-read-me-button col-4" onClick={this.handleOpenDialog.bind(this, item._id)}>Read </Button>
{ isAuthenticated && (item.blog_by === user._id) ?
<span className="col=8">
<Button className="remove-btn-blog-post"
color="danger"
size="sm"
onClick= {this.onDeleteBlogClick.bind(this, item._id)} title="Delete Blog">
×
</Button>
<a className="btn edit-btn-blog-post" href="#" onClick={this.replaceModalItem.bind(this, item._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
{/* <a className="btn edit-btn-blog-post" href="#" onClick={this.handleEditOpenDialog.bind(this, item._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a> */}
</span> : null }
</p>
<p style={{ fontStyle:'italic', fontWeight:'bold'}}>By-{item.blog_by_author} <span style={{float:'right',}}>{Moment(item.date).format('Do MMMM YYYY')}</span></p>
</CardActions>
</Card>
</Cell>
))}
</Grid>
</div>
)}
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={6}
totalItemsCount={blogs.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
itemClass='page-item'
linkClass='page-link'
/>
</Container>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
auth: state.auth,
loading: state.apiCallsInProgress > 0
});
export default connect(mapStateToProps, {getBlog, deleteBlog, updateBlog }) (Blogs);
试试下面的
class EditBlog extends Component {
constructor(props) {
super(props);
this.state = {
modal: null,
requiredItem : null,
_id: '',
blog_short_desc: '',
blog_name: '',
blog_desc: '',
blog_image_link: '',
blog_by: '',
blog_by_author: ''
};
this.replaceModalItem = this.replaceModalItem.bind(this);
this.onTodoChange = this.onTodoChange.bind(this);
}
static propTypes = {
auth: PropTypes.object.isRequired,
updateBlog: PropTypes.func.isRequired,
editBlog: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.name
})
}
toggle = (id) => {
this.setState({
modal: id
});
}
componentWillMount() {
this.props.resume["blogs"].map((blog) => {
this.setState({
updatable : false,
_id: blog._id,
blog_short_desc: blog.blog_short_desc,
blog_name: blog.blog_name,
blog_desc: blog.blog_desc,
blog_image_link: blog.blog_image_link,
blog_by: blog.blog_by,
blog_by_author: blog.blog_by_author
});
})
}
replaceModalItem(id) {
this.setState({
openDialog: true,
OpenEditDialog: true,
requiredItem: id
});
}
onTodoChange = (e) => {
this.setState({
[e.target.name] : e.target.value
});
}
onSubmit = (e, id) => {
e.preventDefault();
const updatedBlog = {
blog_short_desc: this.state.blog_short_desc,
blog_name: this.state.blog_name,
blog_desc: this.state.blog_desc,
blog_image_link: this.state.blog_image_link,
blog_by: this.props.auth["user"]._id,
blog_by_author: this.props.auth["user"].name
}
//update blog via updateblog action
this.props.updateBlog(id, updatedBlog, this.props.history);
alert("Blog updated successfully!");
//close modal
e.target.reset();
this.toggle();
}
render(){
return(
<span>
<a className="btn edit-btn-blog-post" href="#" onClick={()=>this.toggle(this.state._id)} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
<Modal
isOpen = {this.state.modal===this.state._id}
toggle = {()=>this.toggle(this.state._id)}
>
<ModalHeader toggle={()=>this.toggle(this.state._id)} style={{fontWeight: "bold"}}>
Edit your blog {this.state.blog_name}
</ModalHeader>
<ModalBody>
<Form onSubmit={e => this.onSubmit(e, this.state._id, )}>
<FormGroup>
<Label for="blogHeading">Blog Heading</Label>
<Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Update one liner"
onChange={this.onTodoChange} value={this.state.blog_short_desc}/>
<Label for="blogName">Blog Name</Label>
<Input type="text" name="blog_name" id="blogName" placeholder="Update blog name"
onChange={this.onTodoChange} value={this.state.blog_name}/>
<Label for="desc1">Description </Label>
<Input type="textarea" name="blog_desc" id="desc1" placeholder="Update your blog"
onChange={this.onTodoChange} value={this.state.blog_desc}/>
<Label for="imageUrl">Image Url</Label>
<Input type="text" name="blog_image_link" id="imageUrl" placeholder="Update image url (Optional)"
onChange={this.onTodoChange} value={this.state.blog_image_link}/>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
>Edit blog</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</span>
)
}
}
const mapStateToProps = state => ({
resume: state.resume,
auth: state.auth
})
export default connect(mapStateToProps, { updateBlog })(EditBlog);
为什么不使用父组件处理所有帖子,而将 <EditBlog /
仅用作功能组件。这是一个例子和相应的 fiddle:
const EditBlog = ({title, content, handleEdit}) => {
return (
<div classname="editblog">
<h1>{title}</h1>
<p>{content}</p>
<button onClick={handleEdit}>Edit</button>
</div>
)
}
class Blog extends React.Component {
constructor(props) {
super(props);
this.state= {
activeBlogs: [
{title: "Heading 1", content: "Content 1"},
{title: "Heading 2", content: "Content 2"}
],
editId: -1,
}
this.handleEdit = this.handleEdit.bind(this);
}
handleEdit(e) {
const {editId, activeBlogs} = this.state;
let newActiveBlogs = [...activeBlogs];
const {name, value } = e.target;
newActiveBlogs[editId]= Object.assign(newActiveBlogs[editId], {[name]: value});
if(editId >= 0) {
this.setState({
activeBlogs: newActiveBlogs
})
}
}
render() {
const {activeBlogs, editId} = this.state;
return (
<div classname="blog">
{activeBlogs.map((item, index) => {
return <EditBlog key={index} {...item} handleEdit={()=>this.setState({editId: index})} />
})}
{editId >= 0 && activeBlogs.length &&
<div classname="modal">
<h2>Edit Modal is open</h2>
<input name="title" value={activeBlogs[editId].title} onChange={this.handleEdit}></input>
<input name="content" value={activeBlogs[editId].content} onChange={this.handleEdit}></input>
<button onClick={()=>this.setState({editId:-1})}>Save</button>
</div>
}
</div>
)
}
}
ReactDOM.render(
<Blog name="Blog" />,
document.getElementById('container')
);